Running DynamoDB Locally: Complete Guide with Docker and Java Options
Developing applications that use Amazon DynamoDB often requires frequent testing and iteration. Running DynamoDB locally provides a cost-effective, internet-independent environment for development and testing, saving both time and money.
This guide covers everything you need to know about running DynamoDB locally, including setup with Docker and the downloadable JAR, connecting your applications, and important limitations to keep in mind.
What is DynamoDB Local?
DynamoDB Local is a downloadable version of Amazon DynamoDB that lets you develop and test applications using a DynamoDB-compatible database on your computer, without accessing the DynamoDB web service. It’s a perfect solution for:
- Developing and testing without incurring AWS costs
- Working offline or in environments with limited internet access
- Running automated tests in CI/CD pipelines
- Learning DynamoDB without AWS account requirements
DynamoDB Local provides most of the functionality of the AWS DynamoDB service, with a few important differences we’ll cover later in this guide.
Dynomate: Modern DynamoDB GUI Client
Built for real developer workflows with AWS profile integration, multi-session support, and team collaboration.
No account needed. Install and start using immediately.
- Table browsing across regions
- Flexible query & scan interface
- AWS API logging & debugging
Running DynamoDB Local with Docker
Using Docker is the simplest way to get started with DynamoDB Local. It requires minimal setup and works consistently across different operating systems and environments.
Prerequisites
- Docker installed on your system
Step 1: Pull the Official DynamoDB Local Image
docker pull amazon/dynamodb-local
Step 2: Run the Container
For basic usage:
docker run -p 8000:8000 amazon/dynamodb-local
You should see output indicating that DynamoDB Local is running on port 8000.
Docker with Persistent Data
By default, data in DynamoDB Local is lost when the container stops. To persist your data between sessions:
# Create a directory for DynamoDB data
mkdir -p ~/dynamodb-local-data
# Run with a volume mount
docker run -p 8000:8000 -v ~/dynamodb-local-data:/home/dynamodblocal/data amazon/dynamodb-local -jar DynamoDBLocal.jar -dbPath /home/dynamodblocal/data
Docker Compose Example
For more complex setups, you might prefer using Docker Compose:
# docker-compose.yml
version: '3.8'
services:
dynamodb-local:
image: amazon/dynamodb-local
container_name: dynamodb-local
ports:
- "8000:8000"
volumes:
- ./dynamodb-data:/home/dynamodblocal/data
command: "-jar DynamoDBLocal.jar -dbPath /home/dynamodblocal/data"
working_dir: /home/dynamodblocal
Start it with:
docker-compose up -d
Running DynamoDB Local with Java JAR
If you prefer not to use Docker, you can download and run the DynamoDB Local JAR file directly.
Prerequisites
- Java Runtime Environment (JRE) version 8.x or newer
Step 1: Download the DynamoDB Local JAR
Download the latest version from the AWS DynamoDB Local download page.
curl -O https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_latest.tar.gz
tar -xzf dynamodb_local_latest.tar.gz
cd dynamodb_local_latest
Step 2: Run the JAR
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
Additional command-line options:
-port <port-number>
: Use a specific port (default is 8000)-dbPath <path>
: Specify a directory for database files-sharedDb
: Use a single database file instead of separate files per credential/region-inMemory
: Run in memory (data will be lost when stopped)-optimizeDbBeforeStartup
: Run offline optimization before startup
Example with custom port and path:
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -port 8080 -dbPath /path/to/data/directory -sharedDb
Connecting to DynamoDB Local
Once DynamoDB Local is running, you’ll need to configure your applications and tools to connect to it instead of the AWS DynamoDB service.
Using AWS CLI
Configure the AWS CLI to use the local endpoint:
# List tables in local DynamoDB
aws dynamodb list-tables --endpoint-url http://localhost:8000
# Create a table
aws dynamodb create-table \
--table-name Users \
--attribute-definitions AttributeName=UserId,AttributeType=S \
--key-schema AttributeName=UserId,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
--endpoint-url http://localhost:8000
# Put an item
aws dynamodb put-item \
--table-name Users \
--item '{"UserId": {"S": "user123"}, "Name": {"S": "John Doe"}}' \
--endpoint-url http://localhost:8000
# Query the table
aws dynamodb scan --table-name Users --endpoint-url http://localhost:8000
Using Python (Boto3)
import boto3
# Connect to local DynamoDB
dynamodb = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
# Create a table
table = dynamodb.create_table(
TableName='Users',
KeySchema=[
{
'AttributeName': 'UserId',
'KeyType': 'HASH'
}
],
AttributeDefinitions=[
{
'AttributeName': 'UserId',
'AttributeType': 'S'
}
],
ProvisionedThroughput={
'ReadCapacityUnits': 5,
'WriteCapacityUnits': 5
}
)
# Wait until the table exists
table.meta.client.get_waiter('table_exists').wait(TableName='Users')
# Add an item
table.put_item(
Item={
'UserId': 'user123',
'Name': 'John Doe',
'Email': 'john@example.com'
}
)
# Query the table
response = table.scan()
for item in response['Items']:
print(item)
Using Node.js (AWS SDK v3)
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const {
DynamoDBDocumentClient,
CreateTableCommand,
PutCommand,
ScanCommand
} = require("@aws-sdk/lib-dynamodb");
// Create DynamoDB client
const client = new DynamoDBClient({
region: "local",
endpoint: "http://localhost:8000"
});
const docClient = DynamoDBDocumentClient.from(client);
async function main() {
// Create a table
try {
await docClient.send(new CreateTableCommand({
TableName: "Users",
KeySchema: [
{ AttributeName: "UserId", KeyType: "HASH" }
],
AttributeDefinitions: [
{ AttributeName: "UserId", AttributeType: "S" }
],
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5
}
}));
console.log("Table created successfully.");
} catch (err) {
console.error("Error creating table:", err);
}
// Add an item
try {
await docClient.send(new PutCommand({
TableName: "Users",
Item: {
UserId: "user123",
Name: "John Doe",
Email: "john@example.com"
}
}));
console.log("Item added successfully.");
} catch (err) {
console.error("Error adding item:", err);
}
// Query the table
try {
const { Items } = await docClient.send(new ScanCommand({
TableName: "Users"
}));
console.log("Scan results:", Items);
} catch (err) {
console.error("Error scanning table:", err);
}
}
main();
Using Java (AWS SDK v2)
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;
import software.amazon.awssdk.services.dynamodb.model.*;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class DynamoDBLocalExample {
public static void main(String[] args) {
// Set up DynamoDB client
DynamoDbClient dynamoDbClient = DynamoDbClient.builder()
.endpointOverride(URI.create("http://localhost:8000"))
// The region is required, but irrelevant for local DynamoDB
.region(Region.US_EAST_1)
// Credentials are required but not actually checked for local DynamoDB
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create("dummy", "credential")))
.build();
// Create table
try {
CreateTableRequest request = CreateTableRequest.builder()
.tableName("Users")
.keySchema(KeySchemaElement.builder()
.attributeName("UserId")
.keyType(KeyType.HASH)
.build())
.attributeDefinitions(AttributeDefinition.builder()
.attributeName("UserId")
.attributeType(ScalarAttributeType.S)
.build())
.provisionedThroughput(ProvisionedThroughput.builder()
.readCapacityUnits(5L)
.writeCapacityUnits(5L)
.build())
.build();
dynamoDbClient.createTable(request);
System.out.println("Table created successfully");
} catch (DynamoDbException e) {
System.err.println("Error creating table: " + e.getMessage());
}
// Add item
try {
Map<String, AttributeValue> item = new HashMap<>();
item.put("UserId", AttributeValue.builder().s("user123").build());
item.put("Name", AttributeValue.builder().s("John Doe").build());
item.put("Email", AttributeValue.builder().s("john@example.com").build());
PutItemRequest request = PutItemRequest.builder()
.tableName("Users")
.item(item)
.build();
dynamoDbClient.putItem(request);
System.out.println("Item added successfully");
} catch (DynamoDbException e) {
System.err.println("Error adding item: " + e.getMessage());
}
// Scan table
try {
ScanRequest scanRequest = ScanRequest.builder()
.tableName("Users")
.build();
ScanResponse response = dynamoDbClient.scan(scanRequest);
response.items().forEach(item -> {
System.out.println("Item: " + item);
});
} catch (DynamoDbException e) {
System.err.println("Error scanning table: " + e.getMessage());
}
}
}
Testing Your Connection
To verify that DynamoDB Local is running correctly:
aws dynamodb list-tables --endpoint-url http://localhost:8000
If DynamoDB Local is running, this command should return a JSON response with an empty list of table names (if you haven’t created any tables yet).
Familiar with these Dynamodb Challenges ?
- Writing one‑off scripts for simple DynamoDB operations
- Constantly switching between AWS profiles and regions
- Sharing and managing database operations with your team
You should try Dynomate GUI Client for DynamoDB
- Create collections of operations that work together like scripts
- Seamless integration with AWS SSO and profile switching
- Local‑first design with Git‑friendly sharing for team collaboration
Usage Tips for DynamoDB Local
Throughput Considerations
When using DynamoDB Local, throughput settings (ReadCapacityUnits and WriteCapacityUnits) are required but not enforced. You can specify any values, and your operations won’t be throttled.
Data Persistence
- In-memory mode: Data is lost when DynamoDB Local stops
- File mode: Data is saved to disk and persists between restarts
- Shared database mode: All clients use the same database file instead of separate ones per AWS credentials/region
Working with Multiple Applications
You can share a single DynamoDB Local instance among multiple applications by using the -sharedDb
flag. This simplifies testing across different components.
Resetting the Database
If you need to start fresh, you can:
- Delete the data files (if using file mode)
- Stop and restart the container with the
-inMemory
flag - Use the AWS CLI to delete and recreate your tables:
# Delete all tables
for table in $(aws dynamodb list-tables --endpoint-url http://localhost:8000 --query 'TableNames' --output text); do
aws dynamodb delete-table --table-name $table --endpoint-url http://localhost:8000
done
Limitations of DynamoDB Local
While DynamoDB Local is excellent for development and testing, it has some important limitations compared to the AWS DynamoDB service:
Features Not Supported
- DynamoDB Streams: The change data capture feature is not fully supported
- Global Tables: Multi-region replication is not available
- Time to Live (TTL): While the API is present, actual automatic expiration doesn’t occur
- On-demand capacity mode: While the API accepts this setting, it doesn’t function exactly as in AWS
- AWS Identity and Access Management (IAM): Authentication and authorization are minimal
- AWS CloudWatch integration: Metrics are not published
- Some transactional APIs: May have partial implementation
Performance Differences
DynamoDB Local performance depends on your local hardware and isn’t representative of the AWS service’s performance. Don’t use it for performance benchmarking.
Consistency Model
While DynamoDB Local supports the ConsistentRead
parameter, its actual consistency behavior might differ from the AWS service since it’s a single-node implementation.
Using DynamoDB Local in CI/CD Pipelines
DynamoDB Local is perfect for integration testing in continuous integration environments. Here’s a simple example for GitHub Actions:
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
dynamodb:
image: amazon/dynamodb-local
ports:
- 8000:8000
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
DYNAMODB_ENDPOINT: http://localhost:8000
Best Practices
Local Development Workflow
- Use Docker Compose to start both your application and DynamoDB Local together
- Create a startup script that initializes tables and sample data
- Use environment variables to switch between local and AWS endpoints
- Consider using
.aws/credentials
profiles for different environments
Data and Schema Management
- Version control your table schemas and initialization scripts
- Create seed data for testing different scenarios
- Use the same table structure locally as in production
Testing
- Reset the database before each test suite
- Run tests in parallel using different table names or databases
- Simulate error conditions by intercepting SDK calls
Switching from Dynobase? Try Dynomate
Developers are switching to Dynomate for these key advantages:
Better Multi-Profile Support
- Native AWS SSO integration
- Seamless profile switching
- Multiple accounts in a single view
Developer-Focused Workflow
- Script-like operation collections
- Chain data between operations
- Full AWS API logging for debugging
Team Collaboration
- Git-friendly collection sharing
- No account required for installation
- Local-first data storage for privacy
Privacy & Security
- No account creation required
- 100% local data storage
- No telemetry or usage tracking
Conclusion
Running DynamoDB locally provides significant advantages for development and testing, including cost savings, offline capabilities, and faster iteration cycles. Whether you choose Docker or the JAR file approach, DynamoDB Local offers a convenient way to work with a DynamoDB-compatible database without accessing AWS.
Remember to account for the limitations when designing your test strategies, particularly around features that aren’t fully supported in the local version.
Looking for a more powerful way to interact with DynamoDB, both locally and in the cloud? Dynomate provides an intuitive GUI that connects to both DynamoDB Local and AWS DynamoDB, making it easier to visualize your data, design tables, and build queries without writing code.
For more information about working with DynamoDB, check out our related articles: