AWS News Blog
Test your applications against AWS locally with AWS Emulator
|
|
Today we’re announcing AWS Emulator, a local emulator for Amazon Web Services (AWS) that you run on your machine. The AWS Command Line Interface (AWS CLI), the AWS SDKs, and your coding agents speak to it over a local HTTPS endpoint using the same AWS APIs they would use in the cloud, from your laptop. AWS Emulator has no additional service fee. You pay only for AWS resources when you deploy on AWS. Its source is on GitHub. You install it from an RPM or Debian package on Linux, and on macOS and Windows you run it in Docker.
How it works
You install the emulator, start it, and point your tools at the local endpoint. When AWS Emulator starts, it generates its own credentials, a config file, and a certificate, and writes them to ~/.aws/emulator/9297/. You set environment variables so the AWS SDK talks to your laptop instead of AWS, and your application code stays unchanged.
From there, your existing tests, CLI scripts, and coding agents keep working the way they already do. A unit test that creates an Amazon DynamoDB table, writes an item, and reads it back is the same test, and it runs on your machine without a deployment. A coding agent can create resources, check the result, and iterate again without waiting on a deployment in a Region.
The emulator is implemented in Rust so that it stays light on CPU and memory on a laptop. It supports the APIs of AWS services that have an API model in the AWS API models repository on GitHub, and because it’s built from those models, the same ones the AWS SDKs use, your requests and the errors you get back have the same shape as on AWS.
If you are a developer, especially one working with coding agents such as Kiro or Claude Code, you can use that loop to test AWS interactions of real complexity locally.
Let’s try it out
To get started, I installed the package on Amazon Linux 2023. The package adds the aws-emulator command to /usr/bin/, so it’s on the path.
PKG=https://downloads.aws.com/aws-emulator/packages/aws-emulator/LTS/latest sudo dnf install -y $PKG/aws-emulator-x86_64.rpm aws-emulator -v
On macOS and Windows, you build a Docker image from the short Dockerfile in the documentation and run the emulator in a container. We don’t publish a ready-made image.
I started the emulator with aws-emulator. It serves HTTPS on 127.0.0.1:9297, so only my own computer can reach it, and it writes its log as JSON lines that show the address, the config file, and the certificate file.
aws-emulator
In another terminal, I set the environment variables that point the AWS CLI at the emulator, and unset any variables that could supply real AWS credentials.
export AWS_ENDPOINT_URL=https://127.0.0.1:9297 export AWS_SHARED_CREDENTIALS_FILE=~/.aws/emulator/9297/emulator_credentials export AWS_CONFIG_FILE=~/.aws/emulator/9297/config export AWS_EC2_METADATA_DISABLED=true export AWS_DISABLE_HOST_PREFIX_INJECTION=true export AWS_REGION=us-east-1 export AWS_DEFAULT_REGION=us-east-1 unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN AWS_PROFILE
The emulator generates new keys each time it starts. Its access key IDs start with EMULATOR, so you can’t mistake them for real AWS keys, and it rejects requests signed with any other keys. To confirm that my shell was talking to the emulator, I checked the health endpoint and the caller identity. The emulator uses a single account, 000000000000.
curl --cacert ~/.aws/emulator/9297/ca.pem https://127.0.0.1:9297/__admin/health aws sts get-caller-identity
Then I created a bucket, copied in a small object, and listed it.
$ aws s3 mb s3://local-getting-started make_bucket: local-getting-started $ echo "hello from the emulator" > hello.txt $ aws s3 cp hello.txt s3://local-getting-started/ upload: ./hello.txt to s3://local-getting-started/hello.txt $ aws s3 ls s3://local-getting-started/
With the AWS CLI pointed at my laptop, I had the same commands I already use and a local endpoint that answered them.
Next I wanted to see it the way I actually work now, so with the emulator still running I opened Kiro and asked it to create an Amazon DynamoDB table, write an item, and read it back, all against AWS Emulator rather than my AWS account.
kiro> Using the local AWS Emulator (the environment variables
are already set in this shell), create a DynamoDB table
"kiro-demo" with a string key "id", put an item
{id: "item-1", msg: "hello from kiro"}, then read it
back with get-item.
$ aws dynamodb create-table --table-name kiro-demo \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
$ aws dynamodb put-item --table-name kiro-demo \
--item '{"id": {"S": "item-1"}, "msg": {"S": "hello from kiro"}}'
$ aws dynamodb get-item --table-name kiro-demo --key '{"id": {"S": "item-1"}}'
To use the same setup with an existing test suite, I would start the emulator, set the same environment variables in the script that runs the tests, and run them as usual.
Using the emulator in process
Running the emulator as a local process gives you an HTTPS endpoint that works with the AWS CLI and the AWS SDKs through environment variables. Some SDKs need an extra setting to trust the emulator certificate, for example a trust store for the AWS SDK for Java. For tests, there is a second option. AWS Emulator ships an embedded mode that you instantiate directly inside your test process and wire into the SDK through its HTTP client, rather than talking to a separate server over the network. Each embedded instance keeps its own state, so tests do not share buckets, tables, or queues, and you can run many of them in parallel. Embedded mode is available for the AWS SDK for Rust. You add the aws-emulator-embedded crate from GitHub to the [dev-dependencies] section of your Cargo.toml file. The following example creates an Amazon DynamoDB table, writes an item, and reads it back, entirely in process.
use aws_emulator_embedded::{AwsEmulatorEmbedded, EmbeddedOptions};
use aws_sdk_dynamodb::types::{
AttributeDefinition, AttributeValue, BillingMode, KeySchemaElement, KeyType,
ScalarAttributeType,
};
#[tokio::test]
async fn put_then_get_returns_the_item() {
let emulator = AwsEmulatorEmbedded::new(EmbeddedOptions::default());
let config = aws_config::defaults(aws_config::BehaviorVersion::latest())
.http_client(emulator.http_client())
.region(aws_config::Region::new("us-east-1"))
.credentials_provider(emulator.aws_credentials_provider())
.load()
.await;
let ddb = aws_sdk_dynamodb::Client::new(&config);
ddb.create_table()
.table_name("emulator-demo-table")
.attribute_definitions(
AttributeDefinition::builder()
.attribute_name("id").attribute_type(ScalarAttributeType::S)
.build().unwrap())
.key_schema(
KeySchemaElement::builder()
.attribute_name("id").key_type(KeyType::Hash)
.build().unwrap())
.billing_mode(BillingMode::PayPerRequest)
.send().await.unwrap();
ddb.put_item()
.table_name("emulator-demo-table")
.item("id", AttributeValue::S("item-1".into()))
.item("msg", AttributeValue::S("hi".into()))
.send().await.unwrap();
let got = ddb.get_item()
.table_name("emulator-demo-table")
.key("id", AttributeValue::S("item-1".into()))
.send().await.unwrap();
assert_eq!(got.item().unwrap().get("msg").unwrap().as_s().unwrap(), "hi");
}
When it runs as a local process, the emulator requires every request to be signed with Signature Version 4 (SigV4), the same way AWS does, and it exposes a /__admin/health endpoint on the same port so a script or a container can wait until it is ready before running tests. By default it also sends anonymous usage and error data, and you can turn it off.
How we measure fidelity
An emulator is only useful if a test that passes against it would also pass against AWS, so we measure that directly with fidelity tests. A fidelity test is a short program that uses an AWS SDK to run a workflow, such as storing an object and then reading and deleting it, and asserts how AWS behaves. We verify each fidelity test against real AWS. A fidelity test passes only if the emulator matches AWS on the response to every call, including the status code, the body, and the exact error code and message, and on the resources and data that the workflow creates.
With each release, we publish how many fidelity tests pass for each service, as k of n. For example, 40 of 50 means that 40 of the service’s 50 fidelity tests pass. The set of fidelity tests is public in the aws-emulator-evaluation-suite repository on GitHub, including the ones that don’t pass yet, so you can see what we verified and run the fidelity tests yourself. Read a score as a snapshot of a product that’s improving. When we add fidelity tests, a score can go down even while the emulator gets better.
If the emulator doesn’t implement an operation yet, it returns HTTP 501 (Not Implemented), so your tests fail right away. If the emulator acts differently from AWS, you can tell us by opening an issue in the AWS Emulator repository on GitHub.
How the emulator is built
AWS Emulator is built and maintained by agents from the AWS API models using Amazon Bedrock AgentCore Runtime Instances, AWS CodePipeline, and AWS CodeCommit, so it stays current with AWS as those models change.
One group of agents looks for gaps, both by comparing emulator responses against real AWS and by statically comparing the emulator’s code against the published Smithy models, and files an issue for each gap it finds. Another group picks up an issue, writes tests, implements the behavior, and reviews the change for correctness, performance, and security. When the change is ready, it is pushed to a source repository, and that push triggers an AWS CodePipeline run that runs the fidelity tests before the change is published to the public GitHub repository.
How we keep it secure
Because the code is written by agents, an independent security agent reviews changes adversarially, both while the fix is being made and again in the release pipeline as a final check before anything ships.
Security of your own use remains a shared responsibility. We build the emulator to run safely on your machine: it listens only on your own computer by default and rejects requests that aren’t signed with its own keys. You decide where it runs, what data you put in it, and how you test before production. Don’t use the emulator to test whether your application is secure. It doesn’t evaluate AWS Identity and Access Management (IAM) policies and resource-based policies the way AWS does, so a request that AWS denies might succeed in the emulator. Keep real credentials out of the environment of your test jobs, and test your security settings and your whole application on AWS before you go to production.
Now available
AWS Emulator is generally available today. It has no additional service fee. You pay only for AWS resources when you deploy on AWS. You can install it from RPM or Debian packages on Linux, run it in Docker on macOS and Windows, or build from source, and it works with the AWS SDKs and the AWS CLI once you set environment variables. At launch, it has some limits. It doesn’t evaluate IAM policies the way AWS does, and each emulator acts as a single account, with no cross-account or cross-Region behavior. How closely it matches AWS varies by service and feature. To see how well the emulator covers the services that you use, check the fidelity scores in the AWS Emulator documentation.
If you want to check regional availability, visit the AWS Capabilities by Region page in AWS Builder Center. If you want to call APIs, search documentation, find regional availability, and check troubleshooting about this new feature, try using the AWS MCP Server and plugins with your preferred AI tool.
To get started, see the AWS Emulator documentation.
