dynobase-icon
Dynobase

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

Rafal Wilinski

Written by Rafal Wilinski

Last updated: September 19th, 2026

Still using AWS console to work with DynamoDB? 🙈

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.

Endpoint http://localhost:8000. Data lives in shared-local-instance.db.
Docker
docker run --rm \
  -p 8000:8000 \
  -v "$PWD/docker/dynamodb:/home/dynamodblocal/data" \
  amazon/dynamodb-local:latest \
  -jar DynamoDBLocal.jar -sharedDb -dbPath ./data -disableTelemetry
As written this is for bash or zsh. On PowerShell or cmd, put it on one line and replace $PWD with the absolute folder path.
docker-compose.yml
services:
  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
Then docker compose up -d. The jar listens on 8000 inside the container; the port you chose is the host mapping. The health check uses the curl that ships in the image.
The jar directly (needs JRE 17 or newer)
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb -dbPath . -disableTelemetry
Environment for the CLI and SDKs
export 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:8000
The key and secret are not checked, but they cannot be blank, and the key ID names the database file when the shared option is off. Both region variables are set because boto3 and the CLI read AWS_DEFAULT_REGION while the JavaScript and Java SDKs read AWS_REGION. AWS_ENDPOINT_URL_DYNAMODB is honoured by CLI 2.13 and newer and by current SDKs (Java from 2.28.1), so the endpoint need not be repeated on every command.
AWS CLI
aws dynamodb list-tables --endpoint-url http://localhost:8000 --region us-east-1
With AWS_ENDPOINT_URL_DYNAMODB exported, --endpoint-url can be dropped on CLI 2.13 or newer. Older CLIs need it on every call.
JavaScript, SDK v3
import { 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)
Python, boto3
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",
)
Go, SDK v2
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")
})
Java, SDK v2
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();
Once a table exists, point Dynobase at the same endpoint to browse and edit it.

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.

Dynobase is a Professional GUI Client for DynamoDB

Start your 7-day free trial today

Product Features

Download
/
Pricing
/
Member Portal
/
Privacy
/
EULA
/
Twitter
© 2026 Dynobase