DynamoDB
AWS SDK
Java
Pagination
DynamoDBMapper

Pagination with DynamoDBMapper Java AWS SDK

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

With DynamoDBMapper in AWS SDK for Java v1, pagination is usually lazy rather than page-number based. The important distinction is that a query or scan can return a list that fetches more data on demand, while explicit page-oriented methods such as queryPage and scanPage give you tighter control over one page at a time.

Understand the Default Lazy Pagination Model

When you call mapper.query(...) or mapper.scan(...), you often get a paginated list rather than a fully materialized result set. That means DynamoDBMapper may fetch more results as your code iterates.

java
1DynamoDBQueryExpression<Order> expression = new DynamoDBQueryExpression<Order>()
2    .withHashKeyValues(orderKey)
3    .withLimit(25);
4
5PaginatedQueryList<Order> orders = mapper.query(Order.class, expression);
6
7for (Order order : orders) {
8    System.out.println(order.getOrderId());
9}

This is convenient, but it can surprise developers who assume the whole query ran immediately. The list may trigger additional network calls while you iterate.

Use queryPage When You Need Explicit Pages

If you want one page at a time, use queryPage instead of relying on lazy iteration:

java
1DynamoDBQueryExpression<Order> expression = new DynamoDBQueryExpression<Order>()
2    .withHashKeyValues(orderKey)
3    .withLimit(25);
4
5QueryResultPage<Order> page = mapper.queryPage(Order.class, expression);
6
7for (Order order : page.getResults()) {
8    System.out.println(order.getOrderId());
9}
10
11System.out.println(page.getLastEvaluatedKey());

This gives you a page of results plus the LastEvaluatedKey, which is the token DynamoDB uses to continue from where the previous page stopped.

Continue to the Next Page

To fetch the next page, feed that key back into the next request:

java
1Map<String, AttributeValue> lastKey = page.getLastEvaluatedKey();
2
3if (lastKey != null) {
4    expression.setExclusiveStartKey(lastKey);
5    QueryResultPage<Order> nextPage = mapper.queryPage(Order.class, expression);
6}

This is the right approach when you are building APIs or UIs that need deterministic page boundaries rather than a lazily expanding list.

Use the Same Pattern for Scans

Scans work similarly, but keep in mind that a scan reads broadly across the table and is usually much more expensive than a targeted query.

java
1DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
2    .withLimit(50);
3
4ScanResultPage<Customer> scanPage = mapper.scanPage(Customer.class, scanExpression);
5
6for (Customer customer : scanPage.getResults()) {
7    System.out.println(customer.getCustomerId());
8}

If you are paginating scans in production code, first ask whether the access pattern should really be modeled as a query instead.

Choose the Model That Fits the Use Case

A practical rule is:

  • use query or scan when lazy iteration is acceptable
  • use queryPage or scanPage when you need real page boundaries and continuation tokens

This distinction matters because DynamoDB does not support classic page-number pagination efficiently. Its natural paging model is continuation-key based.

Keep the Caller in Control

If you are building a service layer, return the page results together with the continuation key rather than hiding paging behind a full list. That makes cost and latency easier to reason about and keeps the API aligned with DynamoDB's native access pattern.

Common Pitfalls

  • Treating PaginatedQueryList as if it were already fully loaded in memory. Additional requests may happen during iteration.
  • Assuming withLimit means “total results I will ever receive.” It usually means per-request limit, not complete query cap.
  • Building page-number APIs on top of DynamoDB instead of using continuation keys.
  • Using scans for user-facing pagination when a queryable access pattern would be cheaper and more predictable.
  • Forgetting to pass LastEvaluatedKey back into the next request when doing explicit paging.

Summary

  • DynamoDBMapper pagination is usually lazy by default.
  • 'query and scan return paginated lists that may fetch more data on demand.'
  • 'queryPage and scanPage are better when you need explicit page control.'
  • Use LastEvaluatedKey and ExclusiveStartKey to continue to the next page.
  • Prefer queries over scans whenever the data model allows it.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.