Call
Databases

DynamoDB Data Modeling: Partition Keys, Sort Keys, GSIs, Hot Partitions, and Consistency

Design DynamoDB around access patterns: choose partition and sort keys, add GSIs deliberately, avoid hot partitions and scans, choose capacity/consistency correctly, and use conditional writes, TTL, Streams, and global tables safely.

Published: May 27, 2025
Updated: September 12, 2026
10 min read
DynamoDB Data Modeling: Partition Keys, Sort Keys, GSIs, Hot Partitions, and Consistency

DynamoDB Data Modeling: Partition Keys, Sort Keys, GSIs, Hot Partitions, and Consistency

DynamoDB is a serverless key-value and document database, but the most important design work happens before creating the table. Unlike a relational database, you should start from the application's access patterns and design keys/indexes that answer those patterns directly.

A good DynamoDB schema can scale with very little operational work. A poor partition key or scan-heavy design can throttle, cost more than expected, and make simple product requirements difficult to implement.

Start from access patterns

Do not begin with a normalized entity diagram and assume queries can be invented later.

Write down the requests the application must serve:

get one order by tenant + order ID
list recent orders for a tenant
find a user by email
list open jobs by status and creation time

Then map each important request to:

  • base-table primary key
  • sort-key condition
  • local/global secondary index where necessary

If a critical query requires repeatedly scanning the entire table, the data model is probably incomplete.

Partition key and sort key

A DynamoDB primary key can be either:

Simple primary key

partition key only

Example:

user_id = u_42

Each partition-key value identifies one item.

Composite primary key

partition key + sort key

Example:

PK = TENANT#t7
SK = ORDER#2026-09-12#o900

Multiple items can share the same partition key as long as their sort keys differ.

That creates an item collection: related records stored under one partition key and ordered by the sort key.

Sort keys are more than uniqueness

A well-designed sort key can encode hierarchy and support range queries.

For example:

PK = TENANT#t7
SK = ORDER#2026-09-12T08:00:00Z#o900
SK = ORDER#2026-09-12T09:00:00Z#o901

Now one Query can retrieve a tenant's orders in key order or restrict the range by prefix/time.

AWS' current DynamoDB guidance recommends sort-key structures that group related data and support operators such as begins_with and between.

Good sort-key design can avoid extra indexes.

A practical single-table shape

DynamoDB does not require single-table design, but one table can efficiently store related entity types when access patterns overlap.

Example:

PK           SK                         attributes
USER#u1      PROFILE                    name, email
USER#u1      ORDER#2026-09-01#o1        total, status
USER#u1      ORDER#2026-09-08#o2        total, status
TENANT#t7    MEMBER#u1                  role
TENANT#t7    MEMBER#u2                  role

The point is not to put everything into one table as a rule. The point is to shape items so common requests become targeted GetItem or Query operations.

Use multiple tables when ownership, lifecycle, security, throughput, or operational boundaries are clearer that way.

Avoid Scan on hot request paths

Query targets a known partition key and can use sort-key conditions.

Scan reads through items without that targeted key access.

A scan can be acceptable for:

  • small administrative tables
  • one-off operations
  • bounded background maintenance

It is usually a poor core access pattern for a large production table.

If the requirement is “find all orders with status OPEN,” model an index that makes status queryable rather than scanning every order repeatedly.

Global Secondary Indexes create new query keys

A Global Secondary Index (GSI) provides another partition/sort-key view of the table.

Suppose the base table is keyed by user:

PK = USER#u42
SK = ORDER#o900

but the application also needs to look up accounts by email.

A GSI can use:

GSI1PK = EMAIL#asha@example.com
GSI1SK = USER#u42

Now the application can query that access path directly.

Important production properties:

  • GSI key schema can differ from the base table
  • projected attributes determine what the index stores
  • GSI maintenance adds write/storage work
  • GSI updates are asynchronous
  • GSI reads are eventually consistent

An index is not free. Add one because a real access pattern needs it.

Newer multi-attribute GSI keys can reduce synthetic concatenation

Current DynamoDB supports multi-attribute key schemas for Global Secondary Indexes, allowing several attributes to participate in GSI partition and sort keys instead of manually concatenating every domain field into one synthetic string.

That can make some models easier to understand, but the same design questions remain:

  • will the key distribute traffic well?
  • does it support the required query?
  • how large is the index projection?
  • how often will indexed attributes change?

New syntax does not replace access-pattern design.

Partition-key distribution matters

DynamoDB distributes table data across underlying partitions based on partition-key values.

A weak partition key concentrates traffic:

PK = status

If nearly every active item has status = OPEN, one logical key can become extremely hot.

Better keys have enough cardinality and traffic distribution to spread reads/writes.

Potential strategies include:

  • tenant/user/account IDs when traffic is reasonably distributed
  • deterministic write sharding for very hot aggregates
  • time buckets combined with another identifier

Do not add random suffixes blindly: write sharding can make reads more complicated because the application may need to query several buckets and merge results.

Hot partitions and hot items still exist in a serverless database

DynamoDB handles partition management for you, but a very uneven access pattern can still hit per-partition or per-item throughput limits.

AWS documents adaptive capacity, which helps redistribute capacity for uneven traffic, but it is not a reason to design every request around one hot key.

Watch for:

  • one celebrity/user/tenant receiving disproportionate traffic
  • monotonically concentrated writes
  • GSIs with low-cardinality partition keys
  • queue/status indexes where most work sits in one value

Serverless removes server provisioning; it does not remove data-distribution physics.

On-demand vs provisioned capacity

DynamoDB supports two main throughput modes.

On-demand

AWS currently recommends on-demand as the default throughput option for many serverless workloads.

It is useful when:

  • traffic is unpredictable
  • the application is new
  • you do not want to manage read/write capacity units
  • traffic varies substantially

On-demand automatically adapts capacity, though documented scaling behavior and account/table quotas still matter for sudden new peaks.

AWS also supports optional maximum throughput settings on on-demand tables/indexes to bound usage and cost.

Provisioned

Provisioned mode is useful when:

  • workload is predictable
  • you want explicit capacity allocation
  • auto scaling can track the workload effectively

Compare cost using the actual request pattern rather than assuming one mode is always cheaper.

Eventually consistent vs strongly consistent reads

DynamoDB table reads are eventually consistent by default.

For tables and Local Secondary Indexes, a strongly consistent read can be requested when the newest committed item version is required.

Current DynamoDB consistency rules matter:

  • base tables: eventual or strong reads
  • Local Secondary Indexes: eventual or strong reads
  • Global Secondary Indexes: eventual reads only
  • Streams: eventual model

Therefore, if a workflow writes an item then immediately queries a GSI, the index may not reflect the write yet.

Design read-after-write behavior deliberately.

Conditional writes are a core correctness tool

DynamoDB supports conditional expressions so a write occurs only if the current item satisfies a predicate.

Examples:

  • create only if the item does not already exist
  • update only if version equals the expected version
  • decrement inventory only if quantity is sufficient

Conceptually:

Update item
IF version = 17
SET version = 18

This enables optimistic concurrency without a client-side read-then-write race.

Use conditions whenever correctness depends on the previous item state.

Transactions exist—but should not become the default modeling strategy

DynamoDB supports transactional read/write APIs for ACID operations across multiple items within their supported scope.

They are useful for invariants that truly span items.

But if every normal request requires a large transaction across unrelated partitions, the data model may be fighting DynamoDB's strengths.

Prefer schemas where the common operation is naturally local and direct, then use transactions where the business invariant genuinely requires them.

TTL is asynchronous cleanup, not an exact timer

DynamoDB Time to Live allows an item to be marked for automatic expiration based on a timestamp attribute.

TTL is useful for:

  • sessions
  • temporary state
  • idempotency records
  • stale events
  • retention cleanup

Do not use TTL as a precise scheduler. Expired items are removed asynchronously rather than exactly at the timestamp.

Your application should treat an item as logically expired based on its timestamp when exact validity matters.

DynamoDB Streams are a change feed

DynamoDB Streams capture item-level changes and can drive asynchronous workflows.

Common uses:

  • update derived projections
  • trigger Lambda consumers
  • audit/integration pipelines
  • invalidate caches
  • propagate domain changes

Consumers should be idempotent because distributed event-processing systems can encounter retries or repeated delivery semantics depending on the integration path.

Do not perform a fragile synchronous dual write to another system when a durable change/event workflow is more appropriate.

Global tables for multi-Region applications

DynamoDB global tables replicate table data across AWS Regions and allow applications in multiple Regions to operate against local replicas.

Current DynamoDB global tables support two multi-Region consistency modes:

  • multi-Region eventual consistency (MREC)
  • multi-Region strong consistency (MRSC), for supported configurations

The choice materially changes write/read behavior, latency, topology constraints, and cost.

For MREC, concurrent writes to the same item in different Regions can require conflict reconciliation. For MRSC, synchronous multi-Region coordination provides stronger cross-Region read guarantees but introduces different latency/topology trade-offs.

Do not use a global table simply because the application is deployed in multiple Regions. Define the actual regional failure and consistency requirement first.

Secondary indexes add write amplification

Every indexed write can create work not only on the base table but also on applicable GSIs.

If you project a large item into several GSIs, storage and write cost can rise substantially.

For each index, ask:

  • which request uses it?
  • which attributes need projection?
  • how selective/distributed is its partition key?
  • does it create a hot-key pattern?
  • can the access pattern be served by an existing key structure instead?

Indexes should follow access patterns, not speculative future queries.

Large items are expensive

DynamoDB request consumption depends partly on item size.

Storing a large document can make every read/write of that item more expensive and can hit item-size limits.

Do not put huge blobs in DynamoDB. A common architecture stores large binary objects in S3 and keeps identifiers/metadata in DynamoDB.

Also avoid one ever-growing item that contains an unbounded array of child records. Model children as separate items in an item collection when that matches the access pattern.

Cost follows operations and data model

DynamoDB cost can come from several dimensions, including:

  • reads/writes or provisioned throughput
  • item size
  • table/index storage
  • GSIs
  • backups/PITR
  • Streams
  • global-table replication
  • data transfer

A schema that requires repeated scans or maintains many oversized indexes can be expensive even when the application request rate is modest.

Cost optimization starts with data modeling, not only capacity-mode selection.

Observability to keep

Monitor at least:

  • throttled requests
  • consumed read/write capacity where relevant
  • request latency
  • error rate
  • hot-key patterns
  • GSI throttling
  • item/table/index size
  • global-table replication health
  • transaction conflicts/cancellations

CloudWatch metrics show service-level symptoms; application metrics should also identify the logical tenant/key/access pattern producing the pressure.

When DynamoDB is a strong fit

Use it when:

  • access patterns are known and key-oriented
  • horizontal scale/serverless operations are important
  • low-latency key lookups dominate
  • flexible item structure is useful
  • event/change integration with AWS fits the system

When a relational database may be simpler

Prefer PostgreSQL/MySQL-style systems when the product relies heavily on:

  • ad-hoc querying
  • arbitrary joins
  • many evolving access patterns
  • foreign-key relationships
  • complex relational reporting
  • SQL ecosystem/tools

DynamoDB can model sophisticated applications, but complexity does not disappear—it moves into the key/index design.

Production checklist

Before shipping a DynamoDB table, verify:

  1. Every important request has a known GetItem/Query/index path.
  2. The partition key distributes real traffic, not just rows.
  3. Sort keys support the required ranges/hierarchies.
  4. GSIs have a specific justified access pattern.
  5. GSI eventual consistency is acceptable.
  6. Conditional writes protect concurrency-sensitive updates.
  7. TTL is treated as asynchronous cleanup.
  8. Large items and unbounded collections are avoided.
  9. Capacity mode matches workload shape and cost goals.
  10. Hot keys and throttling are observable.
  11. Multi-Region consistency is explicit if global tables are used.

The central DynamoDB skill is not memorizing APIs. It is turning product requests into well-distributed key-based access patterns before production traffic arrives.

Official references

Tags:DynamoDBAWSNoSQLData ModelingServerlessDatabases
ENTERPRISE SAAS ENGINEERING

BUILDING A SAAS PRODUCT?

Explore Lofingo’s end-to-end SaaS platforms, multi-tenant cloud architecture, and high-concurrency backend engineering.

EXPLORE SAAS SERVICES →