construct.with(...) method, and each mixin decides which constructs it supports.
Mixins are the per-construct counterpart to Aspects: a mixin is applied immediately to the one construct you hand it, while an aspect sweeps every construct in a scope during synthesis. See Mixins vs. Aspects below for how to choose.
The mixin primitive — the
IMixin interface and construct.with(...mixins) — has been available in CDK Terrain (CDKTN) since 0.23.0 (cdk-terrain#164), which raised the constructs peer dependency to ^10.6.0 (cdk-terrain#20); CDKTN inherits it from that library. CDKTN does not yet bundle any ready-made mixins in core. You write your own today (this page shows how). Future core releases may ship common mixins based on community use cases, requests, and contributions — the direction is being discussed in RFC-05 in the planning repo; comments and use cases are welcome there.Define a mixin
A mixin is a class that implements theIMixin interface, which has two methods:
supports(construct)— returntrueif this mixin can be applied to the given construct. Use it as a type guard soapplyToonly runs on compatible resources.applyTo(construct)— apply the change. This runs immediately whenwith()is called.
applyTo:
TerraformResource.isTerraformResource(x)— a provider-agnostic guard forsupports.element.addOverride(path, value)— a provider-agnostic escape hatch to set any argument, plus typed setters onTerraformResourcesuch aslifecycle,provider,dependsOn,count, andforEach.
Example: PreventDestroy (provider-agnostic)
This mixin works on any Terraform resource, from any provider. It sets the resource’slifecycle.prevent_destroy so Terraform refuses to destroy it.
TypeScript
with(), which returns the same construct so you can keep a reference:
TypeScript
TypeScript
Example: EnableVersioning (provider-specific)
A mixin can narrowsupports to a specific resource type and configure it. Here addOverride sets the versioning block without depending on a particular provider version’s typed API.
TypeScript
The inline
versioning block on aws_s3_bucket (used here and in the next
example) is deprecated by the AWS provider in favor of the separate
aws_s3_bucket_versioning resource — a real terraform plan prints a
deprecation warning. It is kept here only to make the mixin self-contained;
the mixin technique is identical whichever resource you target.Example: DataRecovery (multiple resource types)
One mixin can support more than one resource type and apply the right change to each — a single “data recovery” feature that enables S3 versioning and DynamoDB point-in-time recovery. It is still applied per-construct withwith().
TypeScript
Mixins vs. Aspects
Mixins and Aspects are complementary. The choice is about where the effect applies and when — not whether it mutates configuration.| Mixin | Aspect | |
|---|---|---|
| Applied to | one construct you hold | every construct in a scope |
| When | immediately, at with() | deferred, during synthesis |
| Reaches constructs you don’t hold (nested, from a library, added later)? | No | Yes |
| Good for | opting a specific resource into a feature | blanket sweeps — tagging, dependency propagation, and validation |
supports check. Use an aspect when you want to cover a whole subtree regardless of what is in it.
The complementary pattern: configure with a mixin, validate with an aspect
A common pairing is a mixin that configures a resource and an aspect that validates the whole app meets a policy — including resources created by third-party libraries that you never callwith() on. This example enforces IMDSv2 on EC2 instances:
TypeScript
ValidateImdsv2 calls Annotations.of(node).addError(...), this is a hard gate, not just an annotation: any Instance that reaches synthesis without IMDSv2 makes app.synth() fail — the error names the offending construct’s path — rather than merely warning. That is what makes the aspect an enforcement backstop for resources nobody remembered to .with(new RequireImdsv2()). Use addWarning instead of addError if you want a nudge rather than a gate.
These examples are shown in TypeScript. The
construct.with(...) primitive is available in every CDKTN language through the inherited constructs.Construct method — note the language-specific names: Python exposes it as with_ and Go/C# as With. See the API reference for the signature in each language.Related resources
- Aspects — apply an operation to every construct in a scope.
- Resources — the
lifecycleblock, escape hatches, andaddOverride. - RFC-05: Mixins — the design discussion and the mixin-vs-aspect analysis behind this page.
- Announcing AWS CDK Mixins — the AWS CDK feature this primitive mirrors (CDKTN inherits it from the shared
constructslibrary).