Learn how to access DynamoDB from a Spring Boot application. We’ll create a few REST APIs and perform CRUD operations on a locally deployed DynamoDB instance. To connect to a remotely deployed instance, only changing the properties shall be sufficient.
1. Intro to AWS DynamoDB
DynamoDB is a fully managed, key-value NoSQL database by Amazon, designed to run high-performance applications at any scale. DynamoDB offers built-in security, continuous backups, automated multi-Region replication, in-memory caching, and data import and export tools. To learn more about DynamoDB, we can check the official documentation.
To avoid creating an AWS account and incurring any cost of running a live instance, let’s install and deploy DynamoDB locally. Check out the instructions on how to set up DynamoDB locally. The local instance will run as an executable JAR file.
Note that currently there is no support planned by AWS SDK team to move from javax.* namespace to jakarta.* namespace, so we may face issues while running DynamoDbLocal with Spring Boot 3 during integration testing.
2. Connecting with DynamoDB
2.1. Maven
To configure and connect with DynamoDB, we must provide the latest version of aws-java-sdk-dynamodb and spring-data-dynamodb dependencies.
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.12.423</version>
</dependency>
<dependency>
<groupId>io.github.boostchicken</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.2.5</version>
</dependency>
2.2. DB Mapper and Client Configuration
Next, let’s add the following connection properties to the application.properties file. Note that the access and secret keys can have any random value for our local setup. When accessing a local instance of DynamoDB, these values are not used for authentication.
For connecting to a remotely installed instance, we can provide the actual keys and endpoint that we get after creating a database instance and a database user in AWS.
aws.dynamodb.accessKey=accessKey
aws.dynamodb.secretKey=secretKey
aws.dynamodb.endpoint=http://localhost:8000
aws.dynamodb.region=ap-south-1
Next, we will be writing a configuration class for DynamoDB, which dynamically pulls properties from the application.properties file using @Value annotation and injects them into the variables defined. Then we will use these variables to configure DynamoDBMapper and connect with DynamoDB.
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
@EnableDynamoDBRepositories(basePackages = {"com.howtodoinjava.demo.repositories"})
public class DynamoDbConfiguration {
@Value("${aws.dynamodb.accessKey}")
private String accessKey;
@Value("${aws.dynamodb.secretKey}")
private String secretKey;
@Value("${aws.dynamodb.region}")
private String region;
@Value("${aws.dynamodb.endpoint}")
private String endpoint;
private AWSCredentialsProvider awsDynamoDBCredentials() {
return new AWSStaticCredentialsProvider(
new BasicAWSCredentials(accessKey, secretKey));
}
@Primary
@Bean
public DynamoDBMapperConfig dynamoDBMapperConfig() {
return DynamoDBMapperConfig.DEFAULT;
}
@Bean
@Primary
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB,
DynamoDBMapperConfig config) {
return new DynamoDBMapper(amazonDynamoDB, config);
}
@Bean
public AmazonDynamoDB amazonDynamoDB() {
return AmazonDynamoDBClientBuilder.standard()
.withEndpointConfiguration(new AwsClientBuilder
.EndpointConfiguration(endpoint, region))
.withCredentials(awsDynamoDBCredentials()).build();
}
}
Let us understand the above configuration –
- AWSCredentialsProvider: is the interface for providing AWS credentials. We are giving static credentials that don’t change, we can also provide complicated implementations, such as integrating with existing key management systems. The caller can use these credentials to authorize an AWS request.
- AmazonDynamoDB: Create a new client for accessing DynamoDB using the endpoint URL, region and credentials.
- DynamoDBMapper: Constructs a new mapper with the service object and configuration given. It enables us to perform various create, read, update, and delete (CRUD) operations on items and run queries and scans against tables.
2.3. Model and Repository
Let’s create a model class MovieDetail. This POJO will use the following AWS-DynamoDB-specific annotations (quite similar to Hibernate) to define the table names, attributes, keys, and other aspects of the table.
- @DynamoDBTable – Identifies the target table in DynamoDB.
- @DynamoDBHashKey – Maps a class property to the partition key of the table.
- @DynamoDBAutoGeneratedKey – Marks a partition key or sort key property as being autogenerated.
DynamoDBMapper
generates a random UUID when saving these attributes. Only String properties can be marked as autogenerated keys. - @DynamoDBAttribute – Maps a property to a table attribute.
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.Data;
@Data
@DynamoDBTable(tableName = "tbl_movie_dtl")
public class MovieDetail {
@DynamoDBHashKey
@DynamoDBAutoGeneratedKey
private String id;
@DynamoDBAttribute(attributeName = "title")
private String title;
@DynamoDBAttribute(attributeName = "year_released")
private Date year;
@DynamoDBAttribute(attributeName = "genre")
private String genre;
@DynamoDBAttribute(attributeName = "country")
private String country;
@DynamoDBAttribute(attributeName = "duration")
private Integer duration;
@DynamoDBAttribute(attributeName = "language")
private String language;
}
Next, we need to create a MovieDetailRepository interface to define the CRUD functionality we want to build out. This interface will interact with DynamoDB to read and persist data.
@org.socialsignin.spring.data.dynamodb.repository.EnableScan;
public interface MovieDetailsRepository extends CrudRepository<MovieDetails, String> {
}
Note that @EnableScan annotation allows us to query the table with an attribute that’s not a partition key. Likewise, we don’t need @EnableScan
when we are querying an index with its partition Key.
2.4. Disable Repository Scanning if Spring Data is Included
By default, if we add the Spring Boot Data (spring-boot-starter-data-jpa) dependency then autoconfiguration tries to enable all JPA repositories in the classpath. We can exclude the dynamodb repository from autoconfiguration as follows:
@SpringBootApplication
@EnableJpaRepositories(excludeFilters =
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = MovieDetailRepository.class))
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
3. Demo
Finally, we will create REST endpoints via controller class to test CRUD operations on DynamoDB.
Create New Movie Record: HTTP POST http://localhost:8080/movies

Fetch All Movies: HTTP GET http://localhost:8080/movies

Delete a Movie by Id: HTTP DELETE http://localhost:8080/movie/{id}

4. Conclusion
This tutorial discussed how to connect to DynamoDB from a Spring Boot Application. By following the discussed steps, we can create the configuration classes and connect with DynamoDB.
Of course, after completing testing locally, we should be able to transparently use a deployed instance of DynamoDB on AWS and run the code with only minor configuration changes in the properties file.
Leave a Reply