Amazon DynamoDB local not only speeds up development and testing iteration loop, it also saves cost of using DynamoDB webservices. Free downloadable version of Amazon DynamoDB (DynamoDBLocal.jar) can run on any operating systems or platform having JRE (Java Runtime Environment).

"This latest version allows Java developers to use DynamoDB local to work with Spring Boot 3 and frameworks such as Spring Framework 6 and Micronaut Framework 4 to build modernized, simplified, and lightweight cloud native applications." -- AWS News

Amazon DynamoDB local is available as
Executable DynamoDBLocal.jar with Libraries
Maven/Gradle dependency
Docker image

In this post we'll explore the first option to install and configure Amazon DynamoDB local version 2.0.

Video:

Prerequisite:

DynamoDB local v2.x requires JRE 11.x or newer. Let's check.

abhijit@AwsJunkie:~$ java --version
openjdk 11.0.19 2023-04-18 LTS
OpenJDK Runtime Environment Corretto-11.0.19.7.1 (build 11.0.19+7-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.19.7.1 (build 11.0.19+7-LTS, mixed mode)

Installation:

Download the latest DynamoDB local.

abhijit@AwsJunkie:~$ curl -O https://d1ni2b6xgvw0s0.cloudfront.net/v2.x/dynamodb_local_latest.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 42.3M  100 42.3M    0     0  7337k      0  0:00:05  0:00:05 --:--:-- 8934k

Unzip it into a new directory (e.g. dynamodb)

abhijit@AwsJunkie:~$ unzip dynamodb_local_latest.zip -d dynamodb
Archive:  dynamodb_local_latest.zip
   creating: dynamodb/DynamoDBLocal_lib/
  inflating: dynamodb/DynamoDBLocal.jar
  inflating: dynamodb/DynamoDBLocal_lib/Apache-HttpComponents-HttpClient-4.5.x.jar 
  inflating: dynamodb/DynamoDBLocal_lib/Apache-HttpComponents-HttpCore-4.4.x.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsFlowJava-1.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-Annotations-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-Auth-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-AwsCore-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-AwsJsonProtocol-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-EndpointsSpi-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-JsonUtils-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-MetricsSpi-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-Profiles-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-ProtocolCore-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-Regions-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-Core-Utils-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-DynamoDb-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-DynamoDb-Enhanced-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-HttpClient-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-HttpClient-ApacheClient-2.0.jar

  inflating: dynamodb/DynamoDBLocal_lib/AwsJavaSdk-HttpClient-NettyNioClient-2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/DynamoDBPartiQLShared-1.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/IonJava.jar
  inflating: dynamodb/DynamoDBLocal_lib/JMESPathJava-1.12.x.jar
  inflating: dynamodb/DynamoDBLocal_lib/JakartaCommons-logging-1.2.jar
  inflating: dynamodb/DynamoDBLocal_lib/Log4j-api-2.x.jar
  inflating: dynamodb/DynamoDBLocal_lib/Log4j-core-2.x.jar
  inflating: dynamodb/DynamoDBLocal_lib/Log4j-slf4j-2.x.jar
  inflating: dynamodb/DynamoDBLocal_lib/annotations-13.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/antlr-runtime-4.5.jar
  inflating: dynamodb/DynamoDBLocal_lib/aws-java-sdk-core-1.12.484.jar
  inflating: dynamodb/DynamoDBLocal_lib/aws-java-sdk-dynamodb-1.12.484.jar
  inflating: dynamodb/DynamoDBLocal_lib/aws-sdk-java-third-party-jackson-core-2.20.90.jar
  inflating: dynamodb/DynamoDBLocal_lib/checker-qual-3.23.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/commons-cli-1.4.jar
  inflating: dynamodb/DynamoDBLocal_lib/commons-lang3-3.12.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/error_prone_annotations-2.18.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/failureaccess-1.0.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/guava-30.1-jre.jar
  inflating: dynamodb/DynamoDBLocal_lib/infinispan-common-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/infinispan-embedded-query-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/infinispan-remote-query-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/ion-element-0.2.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/ion-java-1.5.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/j2objc-annotations-1.3.jar
  inflating: dynamodb/DynamoDBLocal_lib/jackson-annotations-2.12.7.jar
  inflating: dynamodb/DynamoDBLocal_lib/jackson-core-2.12.7.jar
  inflating: dynamodb/DynamoDBLocal_lib/jackson-databind-2.12.7.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/jackson-dataformat-cbor-2.12.7.jar
  inflating: dynamodb/DynamoDBLocal_lib/jackson-datatype-jsr310-2.12.7.jar
  inflating: dynamodb/DynamoDBLocal_lib/jakarta.transaction-api-2.0.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-alpn-client-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-alpn-conscrypt-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-alpn-java-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-alpn-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-annotations-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-cdi-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-client-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-deploy-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-hazelcast-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-http-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-io-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-jaas-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-jakarta-servlet-api-5.0.2.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-jaspi-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-jmx-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-jndi-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-keystore-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-memcached-sessions-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-nosql-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-openid-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-plus-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-proxy-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-quickstart-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-rewrite-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-security-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-servlet-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-servlets-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-unixdomain-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-unixsocket-common-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-unixsocket-server-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-util-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-util-ajax-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-webapp-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/jetty-xml-11.0.11.jar
  inflating: dynamodb/DynamoDBLocal_lib/joda-time-2.12.5.jar
  inflating: dynamodb/DynamoDBLocal_lib/jsr305-3.0.2.jar
  inflating: dynamodb/DynamoDBLocal_lib/kotlin-stdlib-1.6.21.jar
  inflating: dynamodb/DynamoDBLocal_lib/kotlin-stdlib-common-1.6.21.jar
  inflating: dynamodb/DynamoDBLocal_lib/kotlin-stdlib-jdk7-1.3.72.jar
  inflating: dynamodb/DynamoDBLocal_lib/kotlin-stdlib-jdk8-1.3.72.jar
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-linux-aarch64.so
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-linux-amd64.so
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-linux-i386.so
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-osx-aarch64.dylib
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-osx-x86_64.dylib
  inflating: dynamodb/DynamoDBLocal_lib/libsqlite4java-osx.dylib
  inflating: dynamodb/DynamoDBLocal_lib/netty-all-4.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/partiql-ir-generator-runtime-0.4.0.jar
  inflating: dynamodb/DynamoDBLocal_lib/partiql-lang-kotlin-0.3.4.jar
  inflating: dynamodb/DynamoDBLocal_lib/reactive-streams-1.0.4.jar
  inflating: dynamodb/DynamoDBLocal_lib/servlet-api-3.1.jar
  inflating: dynamodb/DynamoDBLocal_lib/slf4j-api-1.7.32.jar
  inflating: dynamodb/DynamoDBLocal_lib/slf4j-ext-1.7.32.jar
  inflating: dynamodb/DynamoDBLocal_lib/sqlite4java-win32-x64.dll
  inflating: dynamodb/DynamoDBLocal_lib/sqlite4java-win32-x86.dll
  inflating: dynamodb/DynamoDBLocal_lib/sqlite4java.jar
  inflating: dynamodb/LICENSE.txt
  inflating: dynamodb/README.txt
  inflating: dynamodb/THIRD-PARTY-LICENSES.txt

You should see DynamoDBLocal.jar and DynamoDBLocal_lib in the unarchived directory.

abhijit@AwsJunkie:~$ cd dynamodb/
abhijit@AwsJunkie:~/dynamodb$ ls
DynamoDBLocal.jar  LICENSE.txt  THIRD-PARTY-LICENSES.txt
DynamoDBLocal_lib  README.txt

Configure:

Configure AWS CLI with dummy AWS Access Key ID and AWS Secret Access Key.

abhijit@AwsJunkie:~/dynamodb$ aws configure
AWS Access Key ID [None]: dummyId
AWS Secret Access Key [None]: dummyKey
Default region name [None]: us-east-1
Default output format [None]:

Run:

Run the java executable DynamoDBLocal.jar with java.library.path (DynamoDBLocal_lib).

abhijit@AwsJunkie:~/dynamodb$ java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
Initializing DynamoDB Local with the following configuration:
Port:   8000
InMemory:       false
DbPath: null
SharedDb:       true
shouldDelayTransientStatuses:   false
CorsParams:     null

It will start at default port 8000.

Verify:

Let's list all tables using AWS CLI command aws dynamodb list-tables. You must pass the --endpoint-url http://localhost:8000

abhijit@AwsJunkie:~$ aws dynamodb list-tables --endpoint-url http://localhost:8000
{
    "TableNames": []
}

Optional:

To avoid typing --endpoint-url http://localhost:8000 for each command, you can create alias in ~./bashrc

abhijit@AwsJunkie:~$ sudo nano ~/.bashrc 

Add alias alias aws='aws --endpoint-url http://localhost:8000'

Reload.

abhijit@AwsJunkie:~$ source ~/.bashrc  

Now you can run without typing --endpoint-url http://localhost:8000

abhijit@AwsJunkie:~$ aws dynamodb list-tables
{
    "TableNames": []
}

Just to play around, try different operations available in the following AWS site Getting started with DynamoDB. For example,

Create Table:

abhijit@AwsJunkie:~$ aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --table-class STANDARD
{
    "TableDescription": {
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "TableName": "Music",
        "KeySchema": [
            {
                "AttributeName": "Artist",
                "KeyType": "HASH"
            },
            {
                "AttributeName": "SongTitle",
                "KeyType": "RANGE"
            }
        ],
        "TableStatus": "ACTIVE",
        "CreationDateTime": "2023-07-07T20:46:43.114000-04:00",
        "ProvisionedThroughput": {
            "LastIncreaseDateTime": "1969-12-31T19:00:00-05:00",
            "LastDecreaseDateTime": "1969-12-31T19:00:00-05:00",
            "NumberOfDecreasesToday": 0,
            "ReadCapacityUnits": 5,
            "WriteCapacityUnits": 5
        },
        "TableSizeBytes": 0,
        "ItemCount": 0,
        "TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/Music"
    }
}

Write Data:

abhijit@AwsJunkie:~$ aws dynamodb put-item \
    --table-name Music  \
    --item \
        '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}'

aws dynamodb put-item \
    --table-name Music  \
    --item \
        '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Howdy"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "2"}}'

aws dynamodb put-item \
    --table-name Music \
    --item \
        '{"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "AlbumTitle": {"S": "Songs About Life"}, "Awards": {"N": "10"}}'

aws dynamodb put-item \
    --table-name Music \
    --item \
        '{"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "PartiQL Rocks"}, "AlbumTitle": {"S": "Another Album Title"}, "Awards": {"N": "8"}}'

Query Data:

abhijit@AwsJunkie:~$ aws dynamodb query \
    --table-name Music \
    --key-condition-expression "Artist = :name" \
    --expression-attribute-values  '{":name":{"S":"Acme Band"}}'
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "AlbumTitle": {
                "S": "Songs About Life"
            },
            "Awards": {
                "N": "10"
            },
            "SongTitle": {
                "S": "Happy Day"
            }
        },
        {
            "Artist": {
                "S": "Acme Band"
            },
            "AlbumTitle": {
                "S": "Another Album Title"
            },
            "Awards": {
                "N": "8"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ],
    "Count": 2,
    "ScannedCount": 2,
    "ConsumedCapacity": null
}

Good to know:

DynamoDB local usage notes:
Except for the endpoint, applications that run with the downloadable version of Amazon DynamoDB should also work with the DynamoDB web service. However, when using DynamoDB locally, you should be aware of the following:

  • If you use the -sharedDb option, DynamoDB creates a single database file named shared-local-instance.db. Every program that connects to DynamoDB accesses this file. If you delete the file, you lose any data that you have stored in it.
  • If you omit -sharedDb, the database file is named myaccesskeyid_region.db, with the AWS access key ID and AWS Region as they appear in your application configuration. If you delete the file, you lose any data that you have stored in it.
  • If you use the -inMemory option, DynamoDB doesn't write any database files at all. Instead, all data is written to memory, and the data is not saved when you terminate DynamoDB.
  • If you use the -optimizeDbBeforeStartup option, you must also specify the -dbPath parameter so that DynamoDB can find its database file.
  • The AWS SDKs for DynamoDB require that your application configuration specify an access key value and an AWS Region value. Unless you're using the -sharedDb or the -inMemory option, DynamoDB uses these values to name the local database file. These values don't have to be valid AWS values to run locally. However, you might find it convenient to use valid values so that you can run your code in the cloud later by changing the endpoint you're using.
  • DynamoDB local always returns null for billingModeSummary.
  • TTL is currently not supported on DynamoDB local.
  • DynamoDB local AWS_ACCESS_KEY_ID can contain only letters (A–Z, a–z) and numbers (0–9).

References