How to Run DynamoDB Locally: Docker, Compose, Jar and SDK Setup

Written by Rafal Wilinski
Last updated: September 19th, 2026
Time to 10x your DynamoDB productivity with Dynobase [learn more]
DynamoDB Local is AWS's downloadable version of DynamoDB, run on your own machine without an account or a bill. Every SDK and the CLI talk to it once you point them at a local endpoint. What goes wrong is the same for everyone: the credentials it insists on, and the database file quietly changing name when your key or region does. The generator below writes every piece so they agree with each other.
Generate your setup
Pick a port, decide whether data survives a restart, and set the region and access key your code will use. You get the Docker command, a Compose file, the plain jar command, the environment variables, and the endpoint configuration for the CLI and four SDKs, all consistent.
http://localhost:8000. Data lives in shared-local-instance.db.docker run --rm \
-p 8000:8000 \
-v "$PWD/docker/dynamodb:/home/dynamodblocal/data" \
amazon/dynamodb-local:latest \
-jar DynamoDBLocal.jar -sharedDb -dbPath ./data -disableTelemetryservices:
dynamodb-local:
image: "amazon/dynamodb-local:latest"
container_name: dynamodb-local
command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data -disableTelemetry"
ports:
- "8000:8000"
volumes:
- './docker/dynamodb:/home/dynamodblocal/data'
working_dir: /home/dynamodblocal
healthcheck:
test: ["CMD", "curl", "-s", "-o", "/dev/null", "http://localhost:8000"]
interval: 5s
timeout: 2s
retries: 10
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb -dbPath . -disableTelemetryexport AWS_ACCESS_KEY_ID=fakeMyKeyId
export AWS_SECRET_ACCESS_KEY=fakeSecretAccessKey
export AWS_DEFAULT_REGION=us-east-1
export AWS_REGION=us-east-1
export AWS_ENDPOINT_URL_DYNAMODB=http://localhost:8000aws dynamodb list-tables --endpoint-url http://localhost:8000 --region us-east-1import { DynamoDBClient } from "@aws-sdk/client-dynamodb"
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"
const client = new DynamoDBClient({
endpoint: "http://localhost:8000",
region: "us-east-1",
credentials: { accessKeyId: "fakeMyKeyId", secretAccessKey: "fakeSecretAccessKey" },
})
const documentClient = DynamoDBDocumentClient.from(client)import boto3
dynamodb = boto3.resource(
"dynamodb",
endpoint_url="http://localhost:8000",
region_name="us-east-1",
aws_access_key_id="fakeMyKeyId",
aws_secret_access_key="fakeSecretAccessKey",
)import (
"context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)
ctx := context.TODO()
cfg, err := config.LoadDefaultConfig(ctx,
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider("fakeMyKeyId", "fakeSecretAccessKey", "")),
)
if err != nil {
panic(err)
}
client := dynamodb.NewFromConfig(cfg, func(o *dynamodb.Options) {
o.BaseEndpoint = aws.String("http://localhost:8000")
})import java.net.URI;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
DynamoDbClient client = DynamoDbClient.builder()
.endpointOverride(URI.create("http://localhost:8000"))
.region(Region.of("us-east-1"))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create("fakeMyKeyId", "fakeSecretAccessKey")))
.build();What DynamoDB Local needs from you
Credentials. The SDKs and the CLI refuse to send a request without an access key, a secret and a region, so DynamoDB Local requires them too, although it never checks them. AWS's own examples use fakeMyKeyId, fakeSecretAccessKey and fakeRegion. One real rule: the access key ID may contain only letters and digits.
A database file, unless you say otherwise. Without -sharedDb, DynamoDB Local names its file after the credentials, myaccesskeyid_us-east-1.db for example, and a request that arrives with a different key or region opens a different, empty file. That is the usual explanation for tables that "disappear" between the CLI and your app. -sharedDb puts everything in one shared-local-instance.db; -inMemory writes nothing and forgets everything on exit, which is what you want in CI.
The endpoint. SDKs take it once in the client constructor. The CLI takes --endpoint-url on every command, or, on CLI 2.13 and newer, reads it once from AWS_ENDPOINT_URL_DYNAMODB, which current SDKs honour too (Java from 2.28.1). At the time of writing AWS's own DynamoDB Local page still says the CLI cannot be given a default endpoint; that stopped being true in July 2023.
Docker
That starts an in-memory-by-default instance with no shared database, which is fine for a quick look and wrong for anything you want to keep. For persistence, mount a folder and pass -dbPath, as the generator does. The jar inside the container always listens on 8000; a different host port is a mapping, not a -port flag.
Docker Compose
AWS's reference file, which the generator extends:
Compose files no longer need a version: line; the current specification ignores it. To run your application alongside, give it depends_on: [dynamodb-local] and use http://dynamodb-local:8000 as the endpoint from inside the network, http://localhost:8000 from your machine. AWS's reference file has no healthcheck, but the image ships with curl (not wget), and DynamoDB Local answers any HTTP request once it is up, so curl -s -o /dev/null http://localhost:8000 is a working test. The generator includes it, and a dependent service can then wait on condition: service_healthy. Relative bind paths in docker run -v need Docker 23 or newer; the generated line uses $PWD, which bash, zsh and PowerShell all expand, so older engines work too. On cmd, use the absolute path.
If the container fails to start or the volume folder is owned by root, see DynamoDB Local Docker not working and unable to open database file.
The jar
Download the archive from AWS's DynamoDB Local page (the archive URLs rotate; the page is the stable link), extract it, and run:
DynamoDB Local 2.6.0 and later needs a Java 17 runtime or newer; it does not start on older ones. On Windows PowerShell, quote the library path argument. -help lists every flag; the ones worth knowing are -port, -dbPath, -inMemory, -sharedDb, -cors for browser clients, -delayTransientStatuses to make index creation take realistic time, and -disableTelemetry. Give the JVM more room with -Xmx2048m if you load a lot of data.
Two errors belong to this route: unable to access jarfile DynamoDBLocal.jar, which is a working-directory problem, and spawn java ENOENT, which means no Java on the PATH.
As a Maven dependency
For Java integration tests, the current line is software.amazon.dynamodb:DynamoDBLocal (3.x, 3.3.1 at the time of writing); the older com.amazonaws coordinates are the 2.x legacy line. Migrating means changing the package prefix from com.amazonaws.services.dynamodbv2 to software.amazon.dynamodb.
LocalStack
LocalStack runs DynamoDB behind its single edge port, 4566, alongside its other services:
Point the endpoint at http://localhost:4566. The awslocal wrapper adds that for every CLI call. If tables you created are missing, or requests hang, see LocalStack DynamoDB not working.
Serverless Framework and Amplify
The plugin to use is serverless-dynamodb, the maintained fork of serverless-dynamodb-local, which stopped working when its hard-coded download URL broke and its maintainers moved on. Same commands: add it under plugins: in serverless.yml, run serverless dynamodb install once to fetch the jar, and serverless dynamodb start --migrate to start it and create the tables you declared under resources. Its README configures region: localhost, which is why the generator accepts a region of that shape.
Amplify's amplify mock api starts a copy too, on port 62224 with region us-fake-1 and access key fake, which is why an app that works under amplify mock needs those exact values to reach the same data from anywhere else. That is Amplify Gen 1, which is in maintenance and reaches end of life on 1 May 2027.
Connecting from the CLI and SDKs
The generator writes these for your values; the shape is the same everywhere, and the Node.js and Python cheat sheets show it in context. Node with SDK v3:
Use http, not https. The EPROTO SSL error people hit here is a client trying to negotiate TLS with a plain HTTP server. If the SDK reports it could not load credentials from any providers, it found no key at all: set the two environment variables or pass credentials in the constructor as above.
Connecting from Dynobase
Dynobase treats a local endpoint like any other connection, so you can browse tables, run queries and edit items in it instead of the CLI. Set the endpoint, region and key under Offline Settings, and make sure at least one table exists first, or the profile has nothing to show. The DynamoDB Local admin GUI page has the walkthrough.
Dynobase is a Professional GUI Client for DynamoDB
Start your 7-day free trial today
Where DynamoDB Local differs from the service
It is for development and testing, and AWS lists the differences plainly. Provisioned throughput numbers are accepted and ignored. Scans run sequentially; Segment and TotalSegments do nothing. Table names are case-insensitive, so Users and users cannot coexist as they can in the cloud. Reads are eventually consistent in name but, as AWS puts it, most look strongly consistent because of the speed of a local instance. Item collection metrics come back null, billingModeSummary is always null, tagging and point-in-time recovery are unsupported, TransactionConflictException is never thrown, the Limit on ExecuteStatement is ignored, and vector indexes are accepted by CreateTable and then silently dropped. Streams work, but shards are created on a different schedule. None of that stops it being the fastest way to develop against DynamoDB. Throughput, contention and consistency have to be tested against the real service.
Troubleshooting
Is it running, and on which port? lsof -i tcp:8000 on Mac or Linux shows a java process listening if so; ps aux | grep DynamoDBLocal shows the flags it started with, including any -port.
"You must specify a region". Nothing to do with DynamoDB Local; the CLI or SDK has no region configured. Set AWS_DEFAULT_REGION or pass --region.
"Unable to locate credentials". Same story: set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to anything non-empty, letters and digits for the key ID. Or keep a named profile for local work with aws configure --profile local and pass --profile local.
Tables I created are gone. Almost always the database file name. Check whether the process was started with -sharedDb; if not, the key and region your app sends must match the ones the CLI used, or you are looking at two files.
Port 8000 is taken. DynamoDB Local refuses to start rather than pick another port. Pass -port, or change the host side of the Docker mapping.