DEV Community

Kenta Goto for AWS Heroes

Posted on

Supercharge AWS Emulator for AWS CDK Development with cdkd

TL;DR

When you use AWS Emulator for development with AWS CDK, combining it with cdkd gives you the following benefits:

  1. cdkd automatically configures the connection to AWS Emulator, and environment variables for Lambda and other resources are resolved automatically from your CDK code, so you don't need a .env file
  2. You can freely switch the connection target per service, for example using real AWS for secrets and reference data/files while having the app write to AWS Emulator (no need to recreate real AWS data locally)
  3. Application code such as Lambda functions runs directly from source without being deployed to AWS Emulator, so you can try out changes right away without redeploying

AWS Emulator and cdkd (CDK Direct)

AWS Emulator is a tool released in November 2026 that emulates AWS APIs locally. It is an emulator that lets you use various AWS resources virtually, without creating them in real AWS.

cdkd (CDK Direct), on the other hand, is a tool that deploys CDK apps quickly by calling the AWS SDK directly, without using CloudFormation. It is an alternative to the CDK CLI for deploying to real AWS environments, but it also provides a subcommand called cdkd local, which lets you run application resources defined in your CDK app, such as Lambda, ECS, API Gateway, CloudFront, and Bedrock AgentCore, locally. For more details on cdkd, see the following article.

I Built cdkd: Deploy Your Existing AWS CDK Code Up to 15x Faster

With the cdkd local command, only the application code runs locally. For the AWS resources the app accesses, you can either use your own emulators or mocks, or connect to resources in a real AWS environment. The latter works because cdkd automatically retrieves and resolves information about the resources the app accesses from your CDK code and deployed stacks.


Two Ways to Use AWS Emulator

There are two main ways to use AWS Emulator. One is to create Lambda functions and other compute inside AWS Emulator and run them there. The other is to run the application code locally and have it access resources, such as tables and buckets, created inside AWS Emulator.

With the former, Lambda in AWS Emulator runs on a built-in implementation rather than the official AWS runtime, so its behavior may differ from real Lambda. Also, although deployments themselves are fast, you have to redeploy to AWS Emulator every time you change the code. With the latter, on the other hand, you need to pass the connection settings for AWS Emulator and information such as the names of the tables to access to the app via environment variables.

When you combine AWS Emulator with cdkd, you use the latter approach, and the responsibilities are split as follows: cdkd creates the resources inside AWS Emulator, and the application code runs in the cdkd local runtime. The results of trying the former approach are summarized in the appendix at the end.


How to Use AWS Emulator + cdkd

In this article, as an example, we use a stack MyStack consisting of a Lambda function that reads from and writes to a DynamoDB table and an S3 bucket, with an API Gateway in front of it.

We use AWS Emulator v1.0.322 and cdkd (@cdkd/cli) v0.349.0. You can install cdkd with the following command.

npm install -g @cdkd/cli
Enter fullscreen mode Exit fullscreen mode

Step 1: Start AWS Emulator

This step has nothing to do with cdkd. It covers installing and starting AWS Emulator itself (exactly as described in the official documentation).

Linux

curl -fsSLo aws-emulator.deb \
  https://downloads.aws.com/aws-emulator/packages/aws-emulator/LTS/latest/aws-emulator_amd64.deb
sudo apt-get install -y ./aws-emulator.deb

aws-emulator -b 0.0.0.0
Enter fullscreen mode Exit fullscreen mode

macOS

# Dockerfile (use aws-emulator-x86_64.rpm on Intel Macs)
FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
ADD https://downloads.aws.com/aws-emulator/packages/aws-emulator/LTS/latest/aws-emulator-aarch64.rpm /tmp/aws-emulator.rpm
RUN rpm -i /tmp/aws-emulator.rpm && rm /tmp/aws-emulator.rpm \
    && mkdir -p /home/emulator && chown 1000 /home/emulator
USER 1000
ENV HOME=/home/emulator
EXPOSE 9297
ENTRYPOINT ["aws-emulator", "-b", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode
docker build -t aws-emulator .
mkdir -p ~/.aws/emulator
docker run --rm -p 127.0.0.1:9297:9297 \
  -e HOME="$HOME" -v "$HOME/.aws/emulator:$HOME/.aws/emulator" \
  aws-emulator -p 9297
Enter fullscreen mode Exit fullscreen mode

Step 2: Create Resources in AWS Emulator

To prepare for running the app code with cdkd local in Step 3, create the resources the app uses inside AWS Emulator. AWS Emulator is empty right after it starts, so you need to create the tables, buckets, and other resources your code reads from and writes to in advance.

cdkd deploy --aws-emulator
Enter fullscreen mode Exit fullscreen mode

To use AWS Emulator, you would normally need to set a number of environment variables for the connection, such as the endpoint, credentials, and certificates (see the official documentation for details). --aws-emulator takes care of all of these settings automatically.

In addition, when you pass --aws-emulator, bootstrapping AWS Emulator is also done automatically under the hood, so you don't need to run cdkd bootstrap (when deploying with cdkd to a real AWS environment instead of AWS Emulator, you need to run cdkd bootstrap once beforehand).

Step 3: Run the App with cdkd local

cdkd local synthesizes the CDK app, then loads the application code from your local source and runs it. It also reads handlers and API routes automatically from your CDK code, so no dedicated configuration file is needed. By passing --aws-emulator, AWS calls from the app are sent to AWS Emulator.

# To start an API server (API Gateway) on localhost
cdkd local start-api --from-state --aws-emulator
curl 'http://127.0.0.1:3000/notes?id=hello'

# To invoke a Lambda function on its own
cdkd local invoke MyStack/Handler --from-state --aws-emulator --event event.json
Enter fullscreen mode Exit fullscreen mode

In practice, the AWS resources a Lambda function accesses are often defined in its environment variables. However, in CDK code (or in a CloudFormation template), those environment variables usually contain references (such as CloudFormation Ref or GetAtt) rather than the actual values of the target AWS resources (the real ARNs or URLs).

So when you specify --from-state, cdkd automatically resolves these references to their actual values using the information recorded in the cdkd stack state during the deployment in Step 2. In other words, developers don't need to define the information about the resources the app accesses in environment variables themselves to run the app locally against the emulator.


Benefits of AWS Emulator + cdkd

From here, I'll explain the three points listed at the beginning (TL;DR).

1. Connection Settings Are Configured Automatically, and Environment Variables for Lambda and Others Are Resolved from CDK Code, So No .env Is Needed

As briefly mentioned in Step 2 above, to use AWS Emulator, you need to set credentials, certificates, and other settings for connecting to it via environment variables (see the official documentation for details).

With cdkd, you just add --aws-emulator to cdkd deploy or cdkd local, and cdkd configures all of these automatically.

Furthermore, as mentioned in Step 3 above, cdkd also automatically resolves the values of environment variables for application resources such as Lambda and ECS.

If you run your app code locally without cdkd, you need to look up auto-generated resource names, ARNs, and so on, copy them into a .env file, and rewrite it every time you recreate the resources. cdkd local reads handlers and environment variables from your CDK code, and with --from-state, it automatically converts references such as table names into their actual values.

Thanks to this mechanism, using cdkd eliminates the need to prepare a .env file. Even if you pass values such as passwords directly via environment variables, cdkd fetches them from Secrets Manager and injects them before startup, so you don't have to keep secret values in local files.

2. Freely Switch Between AWS Emulator and Real AWS Per Service

With cdkd local, you can switch the connection target for each AWS service or database the app accesses. That is, you can achieve flexible setups locally: everything on AWS Emulator, only some resources on real AWS, or all resources on real AWS with only the app code running locally.

Passing --aws-emulator makes every AWS service the app accesses point to AWS Emulator. On top of that, for only the services you want to connect to real AWS, set the value of AWS_ENDPOINT_URL_{resource type} to "real-aws" in the JSON file specified with --env-vars.

For example, in the following example, only Secrets Manager and Cognito use real AWS resources, while DynamoDB, SQS, SNS, S3, and others keep accessing AWS Emulator. You can also split the settings per Lambda function or other unit (write the function name as the key instead of Parameters).

{
  "Parameters": {
    "AWS_ENDPOINT_URL_SECRETS_MANAGER": "real-aws",
    "AWS_ENDPOINT_URL_COGNITO_IDENTITY_PROVIDER": "real-aws"
  }
}
Enter fullscreen mode Exit fullscreen mode

As explained earlier, with --from-state, table names, database endpoints, secret ARNs, and so on are resolved according to the connection target of each service. In the example above, information such as secret ARNs is resolved automatically from real AWS, while table names, queue names, and so on are resolved from AWS Emulator.

Therefore, when you specify "real-aws", you need to run cdkd deploy against real AWS as well beforehand and set up information such as secrets in advance.

# Deploy the stack to both AWS Emulator and real AWS
cdkd deploy --aws-emulator
cdkd deploy # After deploying, set values such as secrets

cdkd local invoke MyStack/Handler --from-state --aws-emulator --env-vars routing.json --event event.json
Enter fullscreen mode Exit fullscreen mode

In fact, by using --from-cfn-stack instead of --from-state, you can retrieve information from a CloudFormation stack deployed with the regular CDK CLI (cdk deploy) rather than a stack deployed with cdkd. This is for those who have just installed cdkd and want to retrieve information from stacks they have been deploying and operating with the regular CDK CLI.

cdkd local invoke MyStack/Handler --from-cfn-stack --aws-emulator --event event.json
Enter fullscreen mode Exit fullscreen mode

With this resource switching feature, cdkd enables setups such as the following:

  • Switch the database between local and a development RDS
    • Keep separate JSON files for connecting to a local MySQL (Docker container) and to a development RDS, and switch between them with --env-vars
    • To connect to something other than AWS resources, such as a local MySQL, write its endpoint in the --env-vars file
  • Use real AWS only for secrets
    • Read API keys for external services such as Stripe or OpenAI from Secrets Manager in real AWS
    • No need to put the actual keys in .env or load them into AWS Emulator, and no hassle of reloading them every time you restart AWS Emulator
  • Use real AWS only for test data and test users
    • Use Cognito test users and S3 files from real AWS
    • Write to DynamoDB and SQS on AWS Emulator
  • Use real models with AI agents
    • Conversation state in DynamoDB (AWS Emulator), models in Bedrock (real AWS)

Currently, switching is done per AWS service, so you can't split it per table within the same DynamoDB. Also, connecting from your local machine to an RDS instance in a private subnet requires a separate tunnel, such as SSM port forwarding.

3. No Redeployment Needed When You Modify App Code

cdkd local reads handlers, environment variables, API routes, and so on directly from your CDK code, and runs application code such as Lambda functions directly from source in Docker, without deploying it to AWS Emulator.

When you emulate Lambda functions entirely inside AWS Emulator, they run on a copy of the code taken at deploy time, so you need to redeploy every time you make a fix. With cdkd local, that isn't necessary, so you can rerun immediately after making changes.


Details of cdkd local + AWS Emulator

For a more detailed explanation of the AWS Emulator integration, see the official cdkd documentation.

AWS Emulator integration - cdkd documentation


You Can Do the Same with cdk-local

The feature of cdkd local that runs your code locally is also published as a standalone tool, cdk-local (command name: cdkl). If you use the CDK CLI and not cdkd, you can use this tool with AWS Emulator in the same way.

npm install -g cdk-local

cdkl invoke MyStack/Handler --from-cfn-stack --aws-emulator --event event.json
Enter fullscreen mode Exit fullscreen mode

Resources are created with the regular cdk deploy, and with --from-cfn-stack, environment variables are resolved automatically from the deployed CDK stack (CloudFormation stack).


Appendix: Running Lambda Inside AWS Emulator

Inside AWS Emulator, you can create and invoke Lambda functions, and you can also send HTTP requests to an API Gateway inside it (you specify the API with the Host header, like curl --cacert ~/.aws/emulator/9297/ca.pem -H 'Host: <api-id>.execute-api.<region>.amazonaws.com' https://127.0.0.1:9297/prod/...). However, those Lambda functions could not connect to anything other than the AWS services provided by AWS Emulator. It currently seems to be designed so that they can't connect to external APIs, local databases, or real AWS.

In addition, as far as I tested with AWS Emulator 1.0.322, the following did not work either:

  • Container image Lambda functions
    • The AWS Emulator registry does not accept image pushes
  • ECS tasks and services, and AgentCore agents
    • The containers are not executed
  • Some standard features of languages (runtimes), such as Node.js fetch, node:zlib, and https, and Python asyncio and ssl
    • Lambda in AWS Emulator runs on a built-in implementation rather than the official AWS runtimes
    • Also, there is only one built-in implementation per language, not one per version (confirmed for Python, and probably the same for Node.js)
  • Some CDK custom resources (Custom::S3AutoDeleteObjects from autoDeleteObjects: true, BucketDeployment, and cr.Provider)
    • The Lambda functions that perform the processing fail to load Node.js https or Python _signal
    • However, when you deploy with --aws-emulator, cdkd runs these Lambda functions on the official runtimes in local Docker instead of inside AWS Emulator, so they work as is (Docker is required)

These findings are as of the time of writing (2026/11/13). All of AWS Emulator's code is written by autonomous AI agents, and development moves so fast that thousands of issues are fixed per day (reference), so this may well change in the future.


Summary

When you use AWS Emulator for development with AWS CDK, combining it with cdkd gives you the following benefits (repeated from above):

  1. cdkd automatically configures the connection to AWS Emulator, and environment variables for Lambda and other resources are resolved automatically from your CDK code, so you don't need a .env file
  2. You can freely switch the connection target per service, for example using real AWS for secrets and reference data/files while having the app write to AWS Emulator (no need to recreate real AWS data locally)
  3. Application code such as Lambda functions runs directly from source without being deployed to AWS Emulator, so you can try out changes right away without redeploying

cdkd has not only fast deployment but also local execution features, so combining it with AWS Emulator makes it even more powerful and extremely convenient.

I also plan to keep adding new features whenever I come up with good ideas.

Top comments (0)