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.

5 min read· Updated Jun 15, 2026
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).

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:

AreaDynamoDB Local
Throughput / throttlingAccepts capacity settings but ignores them — no throttling, ever
Partition limitsNone — won’t reproduce hot-partition problems
Read consistencyConsistentRead is accepted but reads are effectively immediate; you can’t observe real eventual-consistency lag
LatencyLocal, sub-millisecond — not representative
TTLItem expiry is not processed on the real schedule; expired items may linger. See TTL
StreamsSupported, but behavior and timing differ from production. See streams
TransactionsSupported (TransactWriteItems / TransactGetItems)
PartiQLSupported. See PartiQL
IAM, encryption, backups, Global TablesNot 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

  1. Run DynamoDB Local via docker-compose with -sharedDb.
  2. Point your app and tests at http://localhost:8000 via an env var.
  3. Create tables on startup (or in a test fixture) and seed sample data.
  4. Develop and run your integration suite entirely offline.
  5. 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.

Keep reading