Local state — example
Local state is convenient for single-developer experimentation. Here’s an excerpt of a local Terraform state file for the NamePicker app:Remote backend: S3 + DynamoDB (recommended for AWS)
A common production-ready approach on AWS is to store state in an S3 bucket and use a DynamoDB table for state locking. Terraform supports many backends (including Terraform Cloud), but S3 + DynamoDB is a simple, widely-used pattern for teams using AWS. Example: configure the S3 backend in a CDKTF stack so Terraform uses S3 for state and DynamoDB for locking:
Creating the S3 bucket and DynamoDB table
You have three main choices to create the backend resources:- Manual: create the S3 bucket and DynamoDB table in the AWS Console (quick, but not automated or reproducible).
- CDKTF code: add resource definitions in your CDKTF app (automated, but may create circular dependency issues — see below).
- Terraform Registry module: import and reuse a community or org-maintained module (recommended for reproducibility and speed).
cdktf.json and running cdktf get.
Example cdktf.json that references a module:
.gen. A trimmed example of a generated wrapper:

The circular dependency problem (and a warning)
When the same CDKTF app both creates the backend and uses it in the S3Backend configuration, you can hit a circular dependency:- Synthesizing the main app asks “does the remote backend exist?”
- If the backend is defined in the same app, Terraform/CDKTF needs the backend available to synthesize/deploy.
- That creates a circular synth/deploy dependency.
Do not create and use the same S3/DynamoDB backend from a single CDKTF app. Doing so introduces a synth/deploy circular dependency and prevents the app from being synthesized and deployed reliably.

Recommended pattern: split into two apps (prereq + main)
To avoid the circular dependency, split the workflow into two separate CDKTF apps:- A prereq app that creates the S3 bucket and DynamoDB table (local state).
- The main app that uses the created backend (remote S3 state) — it reads the prereq outputs to configure the S3Backend.
- synth & deploy prereq app → creates S3 bucket + DynamoDB table and writes outputs to a local tfstate file.
- synth main app (reads prereq tfstate locally to obtain bucket and table names) → configures S3Backend to point to the created resources.
- deploy main app (now using the remote S3 backend).

Implementation overview
- Create a prereq stack that deploys the S3 bucket and DynamoDB table using the imported module. The prereq stack can use the AWS account ID to create a globally unique bucket name.
- Add an npm script to deploy only the prereq app. Example
package.jsonscripts:
- Use the prereq outputs to configure the main app’s S3 backend. One practical approach is to create a base stack class (for example,
AwsBaseStack) that reads the prereq tfstate file produced by the prereq deployment and configuresS3Backendfrom those outputs.
process.env.INIT_CWDensures the prereq state file is read from the directory where you executed the deploy command.- The prereq stack must be deployed first so the state file containing
bucketanddynamodbTableoutputs is available locally.
- The S3 bucket exists and contains the state key for the main app.
- The DynamoDB table for state locking exists.

- With the
AwsBaseStackreading the prereq outputs, synthesize and deploy the main stack normally. When you run the main deploy (for example,yarn deploy), Terraform should detect no differences against the state stored in S3 if nothing else changed:
Tips:
- CDKTF generates raw Terraform in the
cdktf.outdirectory. If you need to run low-level Terraform commands, usecdktf.outas an escape hatch. - When starting new projects, configure a remote backend from the start. Use the two-app prereq pattern primarily when migrating existing local-state projects.
- Consider using IAM permissions and encryption (KMS) for S3 buckets that hold sensitive state.
Summary
- Local state is convenient for experiments but fragile in team environments. Use a remote backend for collaboration.
- On AWS, S3 + DynamoDB is a common remote backend that provides shared state and locking.
- Avoid creating and using the same backend in a single CDKTF app — this causes a synth/deploy circular dependency.
- Use a two-app pattern (prereq app + main app) to reliably create backend resources and then switch the main app to the remote backend.
- Use
cdktf getto import Terraform Registry modules and.genwrappers to instantiate module constructs in CDKTF.
