AWS Builder Center

AWS CDK: 6 Habits That Keep Your Infrastructure Code Maintainable

Six practical habits that keep AWS CDK infrastructure code readable and safe to change long after the first deploy — from small constructs to reading every cdk diff.

Infrastructure as code has a failure mode nobody warns you about: your CDK app starts clean and six months later it's a 2,000-line stack file that everyone is afraid to touch. I've been there. These six habits are the ones that actually kept my CDK projects readable and safe to change over time.
## 1. Split constructs, not just stacks
The temptation is to create one stack per environment and cram everything into it. Instead, build small reusable constructs — a `MonitoredQueue`, a `PrivateApiWithWaf` — that bundle a resource with its alarms, policies, and sane defaults. Stacks then become thin compositions. When a construct is well-named and well-defaulted, reviewing a change becomes reading a sentence instead of diffing 400 lines of CloudFormation.
## 2. Keep environment-specific values in context, not in code
Hardcoding account IDs, domain names, or CIDR blocks into your app code guarantees a painful merge conflict later. Use `cdk.json` context, environment variables, or SSM Parameter Store lookups (with `fromLookup` style patterns) so the same code deploys to dev, staging, and prod. If I can't deploy the same commit to two environments with zero code edits, something is hardcoded.
## 3. Snapshot-test your synthesized templates
`Template.fromStack` assertions catch accidental drift before it becomes an outage. A snapshot test won't tell you your architecture is wrong, but it will scream when a "small refactor" silently changes an IAM policy or deletes a log group. Run them in CI on every PR. The five minutes they add to the pipeline have saved me from at least two incidents where a renamed construct would have replaced a production database.
## 4. Give every resource an explicit removal policy — on purpose
CDK's defaults try to protect you, but implicit defaults are how stateful resources get destroyed during refactors. For databases, buckets, and anything with data, set `RemovalPolicy.RETAIN` explicitly and write a comment saying why. For everything ephemeral, set `DESTROY` explicitly. Explicit beats implicit every time — future-you won't remember what the default was.
## 5. Version your construct library like a real package
If three teams import your shared constructs, treat the construct library as a product: semantic versioning, a changelog, and deprecation warnings instead of silent breaking changes. Pin versions in consuming apps and upgrade deliberately. Shared infrastructure code without versioning is just distributed copy-paste with extra steps.
## 6. Diff before every deploy, and read the whole diff
`cdk diff` is the cheapest review tool you own. Before `cdk deploy`, read the entire diff — not just the resource names, the property changes too. Diffs that include replacements (`[~]` vs `[-]`/`[+]` semantics in the output) deserve a second pair of eyes. I've caught more mistakes in diffs than in any other part of the deploy process.
## Key takeaways
- Small, well-defaulted constructs keep stacks thin and reviews readable.
- Environment values belong in context/parameters, never hardcoded.
- Snapshot tests in CI catch silent template drift before deploys.
- Explicit removal policies protect data during refactors.
- Version shared constructs; read `cdk diff` fully before every deploy.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article