AWS CDK has newly introduced Mixins as a major feature that will become the core of future CDK development, currently available as a Developer Preview.
This feature is expected to significantly change how CDK will be used in the future.
What are Mixins
As of November 2025, Mixins is in Developer Preview. Please be aware that the specification and behavior may change significantly in the future.
Overview of Mixins
Mixins is a mechanism for applying composable abstractions to any Construct, regardless of whether it's an L1 or L2 Construct.
It was introduced in CDK v2.229.0, but as of November 2025, it is still in Developer Preview. Not all features are fully available yet, and more functionality and improvements are planned to be added in the future.
This article explains the overview and usage of Mixins in a more accessible way, based on the content from the Mixins README and RFC.
- README
-
RFC
- As of November 25, 2025, the RFC has not been merged yet, so the PR link is provided above.
- The RFC is likely not to be merged yet as more features are planned to be added.
Characteristics of Mixins
Mixins enables the partial application of abstractions to L1 Constructs or custom constructs that were traditionally done with L2 Constructs, allowing users to introduce only the features they need without using L2 Constructs.
This makes it possible to selectively introduce only the necessary features, even when some abstractions of L2 Constructs are attractive but others are not desired.
Additionally, when new features are added to AWS services, new properties are immediately reflected in L1 Constructs, but it takes time for them to be reflected in L2 Constructs. By using Mixins, users can easily and safely apply new properties to L2 Constructs (without using escape hatches) before those properties are added to L2 Constructs.
In other words, Mixins reduces the gap between L1 and L2 Constructs, enabling more flexible construct design.
Furthermore, Mixins also provides a mechanism to abstractly apply common patterns such as encryption across various AWS services.
Installation
Since Mixins is still in Developer Preview, it is provided as the @aws-cdk/mixins-preview package.
npm install -D @aws-cdk/mixins-preview
Note
If you encounter errors when running cdk deploy or cdk synth after introducing Mixins in an existing CDK project (TypeScript), first check your tsconfig.json.
The newer version of CDK CLI (2.1033.0) generates the following configuration, so if your project's configuration differs, aligning it may resolve the issue.
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": [
"es2022"
],
...,
...,
"skipLibCheck": true,
}
How to Use Mixins
Mixins are applied using the Mixins.of() method or the with() method of each construct.
The with() method becomes available by importing the @aws-cdk/mixins-preview/with module in the file where you use it (import '@aws-cdk/mixins-preview/with').
NOTE: The .with() method is currently available only in JavaScript and TypeScript. The import is only required during the preview period. Once the API is stable, the .with() method will be available by default on all constructs in all languages.
import { Mixins } from '@aws-cdk/mixins-preview/core';
import '@aws-cdk/mixins-preview/with';
const bucket = new s3.CfnBucket(scope, 'MyBucket');
Mixins.of(bucket) // Mixins
.apply(new EnableVersioning()) // Apply EnableVersioning to bucket
.apply(new AutoDeleteObjects()); // Apply AutoDeleteObjects to bucket
const bucket = new s3.CfnBucket(scope, 'MyBucket')
.with(new EnableVersioning()) // Apply EnableVersioning with Construct's with method
.with(new AutoDeleteObjects()); // Apply AutoDeleteObjects with Construct's with method
You can also apply Mixins to all resources under a specific scope, similar to Aspects.
import { Mixins } from '@aws-cdk/mixins-preview/core';
// Apply to all resources under scope
Mixins.of(scope).apply(new EnableVersioning());
// Apply only to specific resource types under scope
Mixins.of(scope, ConstructSelector.resourcesOfType(s3.CfnBucket)) // Limited to CfnBucket
.apply(new EnableVersioning());
// Apply only to resources matching specific ID patterns under scope
Mixins.of(scope, ConstructSelector.byId(/.*-prod-.*/)) // Limited to resources whose ID contains "-prod-"
.apply(new ProductionSecurityMixin());
Types of Mixins
There are several types of Mixins patterns available:
- Cross-Service Mixins
- Resource-Specific Mixins
- L1 Property Mixins
Cross-Service Mixins
These are Mixins that can be applied across multiple AWS services.
For example, EncryptionAtRest is a Mixin that enables encryption across AWS resources that support it.
NOTE: The EncryptionAtRest Mixin is not yet included in the current CDK release, but it is introduced in the README examples. It is expected to be introduced soon, so this article uses that example as well.
import { Mixins } from '@aws-cdk/mixins-preview/core';
const bucket = new s3.CfnBucket(scope, 'Bucket');
Mixins.of(bucket).apply(new EncryptionAtRest());
const logGroup = new logs.CfnLogGroup(scope, 'LogGroup');
Mixins.of(logGroup).apply(new EncryptionAtRest());
Implementation of other features such as Vended logs is also in progress.
- chore(mixins-preview): vended logs README
- chore(mixins-preview): vended log deliveries and destinations
- chore(mixins-preview): codegen for vended logs mixins
- chore(mixins-preview): delivery destinations for vended logs
Resource-Specific Mixins
Resource-specific Mixins are also available for each AWS service (resource).
For example, there are AutoDeleteObjects, which automatically deletes objects using a custom resource Lambda for S3 buckets, and EnableVersioning, which enables versioning.
By applying these Mixins to L1 Constructs, you can introduce the same abstractions as L2 Constructs without using L2 Constructs.
While versioning can be easily enabled with just L1 Constructs, it is convenient when applying to multiple resources at once, similar to Aspects.
import { Mixins } from '@aws-cdk/mixins-preview/core';
const bucket = new s3.CfnBucket(scope, 'Bucket');
Mixins.of(bucket).apply(new AutoDeleteObjects());
const bucket = new s3.CfnBucket(scope, 'Bucket');
Mixins.of(bucket).apply(new EnableVersioning());
NOTE: However, in the currently released v2.229.0, using AutoDeleteObjects causes an error.
I submitted a PR to fix it, and it has already been merged, so a fixed version should be released soon.
L1 Property Mixins
These are Mixins that allow you to easily apply L1 properties that have not yet been introduced to L2 Constructs.
For example, by passing a Mixin called CfnBucketPropsMixin, which applies L1 properties, to the with() method of an L2 Construct, you can apply L1 properties that have not yet been introduced to L2 Constructs in a typed manner.
Traditionally, applying L1 properties to L2 Constructs required using escape hatches, which had the problem of lacking type safety. Using Mixins makes it easier to apply them in a typed manner.
import { CfnBucketPropsMixin } from '@aws-cdk/mixins-preview/aws_s3/mixins';
import '@aws-cdk/mixins-preview/with';
const bucket = new s3.Bucket(scope, 'Bucket').with(
new CfnBucketPropsMixin({
versioningConfiguration: { status: 'Enabled' },
publicAccessBlockConfiguration: {
blockPublicAcls: true,
blockPublicPolicy: true,
},
}),
);
L1 Property Mixins also provide two merge strategies: MERGE and OVERRIDE.
- MERGE (default): Merge the specified properties into the existing properties
- OVERRIDE: Overwrite the existing properties with the specified properties
import { Mixins } from '@aws-cdk/mixins-preview/core';
import { CfnBucketPropsMixin } from '@aws-cdk/mixins-preview/aws_s3/mixins';
const bucket = new s3.CfnBucket(stack, 'Bucket');
bucket.versioningConfiguration = { status: 'Enabled' };
// MERGE
// versioningConfiguration becomes: { status: 'Enabled', newProperty: 'Disabled' }
// -> status: 'Enabled' remains
Mixins.of(bucket).apply(
new CfnBucketPropsMixin(
{ versioningConfiguration: { newProperty: 'Disabled' } },
{ strategy: PropertyMergeStrategy.MERGE },
),
);
// OVERRIDE
// versioningConfiguration becomes: { newProperty: 'Disabled' }
// -> status: 'Enabled' is removed
Mixins.of(bucket).apply(
new CfnBucketPropsMixin(
{ versioningConfiguration: { newProperty: 'Disabled' } },
{ strategy: PropertyMergeStrategy.OVERRIDE },
),
);
While the two types of Mixins mentioned earlier are implemented individually in the CDK repository, L1 Property Mixins are automatically generated for all L1 Constructs in the CDK repository.
Error Handling
When Mixins are applied using the apply() method, the processing is skipped for resources that do not support that Mixin.
On the other hand, when using the mustApply() method, an error will occur for resources that do not support the Mixin.
If you want to strictly apply Mixins, you should use the mustApply() method.
import { Mixins } from '@aws-cdk/mixins-preview/core';
// Skip if there are resources that do not support EncryptionAtRest under scope
Mixins.of(scope).apply(new EncryptionAtRest());
// An error occurs if there are resources that do not support EncryptionAtRest under scope
Mixins.of(scope).mustApply(new EncryptionAtRest());
Creating Custom Mixins
You can easily create custom Mixins by implementing the IMixin interface.
You can also create one with some of IMixin already implemented by extending the Mixin abstract class.
NOTE: It is recommended to always extend the Mixin abstract class rather than implementing IMixin directly. While the experience is similar, extending Mixin will make future transitions easier for authors.
The following example is a custom Mixin that enables versioning for S3 buckets.
import { Mixin, Mixins } from '@aws-cdk/mixins-preview/lib/core';
// or class CustomVersioningMixin implements IMixin {
class CustomVersioningMixin extends Mixin {
supports(construct: any): boolean {
return construct instanceof s3.CfnBucket;
}
applyTo(bucket: any): any {
bucket.versioningConfiguration = {
status: 'Enabled',
};
return bucket;
}
}
const bucket = new s3.CfnBucket(scope, 'MyBucket');
Mixins.of(bucket).apply(new CustomVersioningMixin());
Differences from Aspects
Mixins are similar to Aspects in that they modify properties of resources in a specific scope, but they differ in timing of application.
Aspects are not executed at call time, but are executed later in the synthesis process of the CDK application (in the Prepare phase after Construct creation is complete in the CDK application lifecycle).
In other words, while Aspects are executed after all Constructs defined in the CDK application have been created, Mixins are executed immediately when they are called.
- Aspects
const construct = new Construct(scope, 'MyConstruct');
new Bucket(construct, 'MyBucket1');
// Executed after Constructs below this are created
Aspects.of(construct).add(new CustomVersioningAspect());
// Aspects are also applied to MyBucket2
new Bucket(construct, 'MyBucket2');
- Mixins
const construct = new Construct(scope, 'MyConstruct');
new Bucket(construct, 'MyBucket1');
// Executed at this point
Mixins.of(construct).apply(new CustomVersioningMixin());
// Mixins are not applied to MyBucket2
new Bucket(construct, 'MyBucket2');
According to the Mixins RFC, it is recommended to use Mixins to make changes and to use Aspects to validate behaviors.
We recommend to use Mixins to make changes, and to use Aspects to validate behaviors.
There are also other differences between Mixins and Aspects, as described below:
With mixins, you make explicit decisions about each construct's capabilities. With aspects, you set policies that the CDK applies automatically during synthesis. Mixins give you precise control and type safety, while aspects provide broad governance and compliance enforcement.
- Mixins
- You can make explicit decisions about each Construct's capabilities
- Provides precise control and type safety
- Aspects
- You can set policies that the CDK applies automatically during synthesis
- Provides broad governance and compliance enforcement
The RFC also mentions that a mechanism will be introduced to convert between Aspects and Mixins, but as of v2.229.0, this feature has not yet been introduced.
// Applies the aspect immediately
Mixins.of(scope).apply(Mixin.fromAspect(new TaggingAspect({ Environment: 'prod' })));
// Delays application of the Mixin to the synthesis phase
Aspects.of(scope).add(Aspect.fromMixin(new EncryptionAtRest()));
Conclusion
Mixins is an important feature that will become the core of future CDK development.
Although it is still in Developer Preview and there are still insufficient features and behaviors, it is worth paying attention to as it has the potential to significantly change how CDK will be used in the future.
Top comments (0)