DynamoDB Local: Run DynamoDB on Your Machine
Set up DynamoDB Local for offline development — Docker and JAR options, endpoint configuration, creating tables, and differences from the real service.
On this page
DynamoDB Local is a self-contained version of DynamoDB that runs on your laptop with no AWS account, no network calls, and no cost. It’s the standard way to develop and run integration tests against DynamoDB without touching the real service. This guide gets you running and flags where local behavior diverges from production.
Why run DynamoDB locally
- Zero cost and zero latency — no per-request billing, no round trips to AWS.
- Offline development — work on a plane, in CI, or behind a firewall.
- Fast, isolated tests — spin up a fresh table per test run and tear it down, no shared state.
- Safe experimentation — break things without affecting any real data.
The tradeoff: it’s an emulator, not the real engine. It’s faithful for the API surface but not for performance, scaling, or some newer features (covered at the end).
Option 1: Docker (recommended)
The official image is the simplest path and the one most teams use in CI.
docker run -d -p 8000:8000 amazon/dynamodb-local
That starts DynamoDB Local listening on port 8000, storing data in memory (gone when the container stops). To persist data across restarts, mount a volume and tell it to write to disk:
docker run -d -p 8000:8000 \
-v "$(pwd)/dynamodb-data:/home/dynamodblocal/data" \
amazon/dynamodb-local \
-jar DynamoDBLocal.jar -sharedDb -dbPath /home/dynamodblocal/data
The -sharedDb flag is important — see the note on it below.
docker-compose
For a repeatable dev setup, drop it in docker-compose.yml:
services:
dynamodb-local:
image: amazon/dynamodb-local
command: "-jar DynamoDBLocal.jar -sharedDb -dbPath /data"
ports:
- "8000:8000"
volumes:
- "./dynamodb-data:/data"
Option 2: Standalone JAR
If you’d rather not use Docker, download the DynamoDBLocal archive from AWS, extract it, and run it directly. It needs a Java runtime (JRE 17+).
java -Djava.library.path=./DynamoDBLocal_lib \
-jar DynamoDBLocal.jar -sharedDb
Same flags apply: add -inMemory for a fast ephemeral store, or -dbPath ./data to persist.
Pointing your client at it
The only change to your application code is the endpoint URL. DynamoDB Local still requires credentials because the SDK insists on them, but it ignores the values — any dummy strings work.
AWS CLI
aws dynamodb list-tables --endpoint-url http://localhost:8000
Set dummy credentials once so the CLI stops complaining:
export AWS_ACCESS_KEY_ID=local
export AWS_SECRET_ACCESS_KEY=local
export AWS_DEFAULT_REGION=us-east-1
boto3 (Python)
import boto3
ddb = boto3.resource(
"dynamodb",
endpoint_url="http://localhost:8000",
region_name="us-east-1",
aws_access_key_id="local",
aws_secret_access_key="local",
)
A clean pattern is to read the endpoint from an env var so the same code talks to local in dev and real DynamoDB in production:
endpoint = os.environ.get("DYNAMODB_ENDPOINT") # set only in dev
ddb = boto3.resource("dynamodb", endpoint_url=endpoint) # None = real AWS
JavaScript (AWS SDK v3)
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({
endpoint: "http://localhost:8000",
region: "us-east-1",
credentials: { accessKeyId: "local", secretAccessKey: "local" },
});
Creating a table locally
Everything works exactly like the real API — just with the local endpoint.
aws dynamodb create-table \
--table-name Users \
--attribute-definitions AttributeName=userId,AttributeType=S \
--key-schema AttributeName=userId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--endpoint-url http://localhost:8000
Then put and query items with the same commands you’d use in production — see how to query DynamoDB for the read operations.
aws dynamodb put-item \
--table-name Users \
--item '{"userId": {"S": "user-1"}, "name": {"S": "Ana"}}' \
--endpoint-url http://localhost:8000
The -sharedDb flag (read this)
By default, DynamoDB Local creates a separate database file per credential/region combination. Since your dummy credentials may vary between tools, you can end up with tables that one client sees and another doesn’t — a confusing “my table disappeared” bug.
The -sharedDb flag forces a single shared database regardless of credentials or region. Almost always use it. Without it, the CLI and your application may be looking at different stores.
Where DynamoDB Local differs from the real service
This is the part that catches people. DynamoDB Local is an API emulator, so several production behaviors are absent or faked:
| Area | DynamoDB Local |
|---|---|
| Throughput / throttling | Accepts capacity settings but ignores them — no throttling, ever |
| Partition limits | None — won’t reproduce hot-partition problems |
| Read consistency | ConsistentRead is accepted but reads are effectively immediate; you can’t observe real eventual-consistency lag |
| Latency | Local, sub-millisecond — not representative |
| TTL | Item expiry is not processed on the real schedule; expired items may linger. See TTL |
| Streams | Supported, but behavior and timing differ from production. See streams |
| Transactions | Supported (TransactWriteItems / TransactGetItems) |
| PartiQL | Supported. See PartiQL |
| IAM, encryption, backups, Global Tables | Not enforced / not available |
The practical takeaway: DynamoDB Local is excellent for functional correctness — does my query return the right items, does my condition expression work, does my migration run — but it cannot validate capacity, throttling, or consistency behavior. Those need the real service or a load test. Don’t conclude “it works locally” means it’ll scale; the things that bite you at scale are exactly what the emulator omits. Review best practices for the production concerns it won’t catch.
A typical workflow
- Run DynamoDB Local via docker-compose with
-sharedDb. - Point your app and tests at
http://localhost:8000via an env var. - Create tables on startup (or in a test fixture) and seed sample data.
- Develop and run your integration suite entirely offline.
- Promote the identical table definitions to real DynamoDB in AWS.
Because the data lives on your own machine, a desktop DynamoDB GUI is handy for inspecting it. A native client like Tablyne connects to a local endpoint the same way it connects to a real AWS table, so you can browse items, run queries, and edit data in your local store without writing throwaway scripts. That makes the dev loop tighter when you’re modeling tables before they ever reach AWS. From here, how to query DynamoDB walks through the read operations you’ll exercise against your local tables.
Frequently asked questions
Is DynamoDB Local free?
Yes. DynamoDB Local is a free downloadable build (Docker image or JAR) that runs entirely on your machine with no AWS account or network calls. You only pay when you point your code at the real DynamoDB service in AWS.
Does DynamoDB Local enforce capacity limits and throttling?
No. It accepts ProvisionedThroughput settings for API compatibility but ignores them — there's no throttling, no partition limits, and no real latency. That means it won't catch hot-partition or capacity bugs; you need the real service or load testing for that.
How do I point the AWS SDK at DynamoDB Local?
Set the endpoint URL to http://localhost:8000 when constructing the client (the --endpoint-url flag on the CLI, or endpoint_url in boto3). Credentials are required by the SDK but ignored, so any dummy access key and secret will work.