DynamoDB Single Table Design — Interview Guide
Reviewed by Gurusankar M. · Updated Aug 24, 2026
Short Answer
Single-table design stores multiple entity types in ONE table, using composite keys (PK/SK) and GSIs crafted so each known access pattern is served by a single efficient query — no joins, no multiple round-trips. It trades modeling complexity and rigidity for low latency and cost at scale.
On this page
Concept Made Simple
Coffee Chat Question
“What is DynamoDB single-table design, and why do experts use it?”
Remember It Faster
Mind Map Answer
- One table
- many entity types together
- Composite keys
- PK/SK model relationships
- GSIs
- serve additional access patterns
- Goal
- one query per access pattern, no joins
| PK | SK | Item |
|---|---|---|
| CUSTOMER#123 | METADATA | Customer profile |
| CUSTOMER#123 | ORDER#001 | Order 1, belongs to this customer |
| CUSTOMER#123 | ORDER#002 | Order 2, belongs to this customer |
| ORDER#001 | METADATA | Order details, fetched directly by order id |
One table, two access patterns, no join: Query PK = CUSTOMER#123 returns the customer's profile and every one of their orders in a single request (they share the same partition). Query PK = ORDER#001 fetches that order's own details directly. The keys are modeled around the *known* access patterns — not around normalized entities the way a relational schema would be.
Overloaded GSIs are what make one table serve many entity types cleanly. Instead of a dedicated index per entity, a single GSI1PK/GSI1SK pair holds different, purpose-built values per item type — for a CUSTOMER item, GSI1PK might be EMAIL#<email> (to look customers up by email); for an ORDER item, the same attribute name might hold STATUS#<status> (to list orders by status). The GSI attribute name is reused ("overloaded"), but each entity type puts a differently-shaped value in it — so one physical index quietly serves several unrelated access patterns instead of one GSI per query.
Adding a genuinely new access pattern later has three levels of cost, in order of preference. Cheapest: if an existing GSI's key already happens to sort/filter the new way you need, you're done — no schema change at all. Next: add a new GSI (GSI2PK/GSI2SK) — DynamoDB backfills it automatically from existing items, no downtime, but every existing item needs the new attribute populated, which for old items means either the application computed it defensively when the item was first written (the standard single-table-design discipline: populate GSI attributes for patterns you might need, not just ones you use today) or a one-time backfill script that scans and updates every item. Most expensive: the new pattern needs a key shape the existing attributes can't produce at all — that usually means a genuinely new item type or a denormalized copy, which is the scenario the whatIf above calls a "painful migration," and exactly why enumerating access patterns up front matters so much more here than in a relational schema.
Sparse GSIs turn "only some items have this attribute" into a free filtered index. A GSI only indexes items that actually have a value for the GSI's key attribute — an item missing that attribute simply doesn't appear in the index at all, rather than appearing with a null key. That's a deliberate feature, not an edge case to work around: give the GSI key attribute a value only on ORDER items where status = PENDING, and the GSI now contains only pending orders — no filter expression needed, no scanning past shipped/delivered orders to find them, because they were never written into the index in the first place. It's the standard single-table-design technique for "give me only the items matching some condition" queries, and it's a favorite follow-up precisely because it looks like a quirky side effect until you see it used deliberately. Because populating the key is what includes an item, removing it from a sparse index is just as deliberate — clear the GSI key attribute (e.g. when an order ships) and the item vanishes from the index on the very next write, no separate cleanup step required.
Learn by Doing
Hands-on Keyboard
// Overloaded GSI: GSI1PK holds different value shapes per entity type,
// so one index serves two unrelated access patterns.
// Item shapes written earlier:
// CUSTOMER#123 -> GSI1PK = "EMAIL#alice@example.com", GSI1SK = "CUSTOMER#123"
// ORDER#001 -> GSI1PK = "STATUS#SHIPPED", GSI1SK = "ORDER#001"
// Pattern A: look up a customer by email — no scan, no separate email-index table
QueryRequest byEmail = QueryRequest.builder()
.tableName("AppTable")
.indexName("GSI1")
.keyConditionExpression("GSI1PK = :pk")
.expressionAttributeValues(Map.of(
":pk", AttributeValue.fromS("EMAIL#alice@example.com")))
.build();
// Pattern B: list every order currently SHIPPED — same index, different key shape
QueryRequest byStatus = QueryRequest.builder()
.tableName("AppTable")
.indexName("GSI1")
.keyConditionExpression("GSI1PK = :pk")
.expressionAttributeValues(Map.of(
":pk", AttributeValue.fromS("STATUS#SHIPPED")))
.build();Two unrelated access patterns (email lookup, status listing) served by one GSI.
Think Beyond the Expected
What If?
Why is single-table design controversial / risky?
You must know ALL access patterns up front — the key/GSI design is baked around them. New, unforeseen query needs can require painful migrations or extra GSIs, and the schema is hard for newcomers to read. It maximizes performance/cost but sacrifices flexibility, so it's not always the right call.
Real World
AWS/Alex DeBrie advocate single-table design for high-scale DynamoDB apps to hit single-digit-ms latency and minimize cost; teams with evolving requirements often prefer simpler multi-table or a relational DB. Overloaded GSIs are usually the detail that trips up engineers new to the pattern — the index looks like it holds one kind of data until you notice the key values are deliberately shaped differently per entity type.
Interviewer's Expectation
Keywords they're listening for:
- multiple entities in one table
- composite PK/SK + GSIs
- one query per access pattern
- must know patterns upfront
- flexibility trade-off
Common Mistakes
- Single-table design with unknown/evolving patterns
- Relational thinking (joins) on DynamoDB
- Not planning GSIs for all patterns
Best Practices
- Enumerate all access patterns first
- Model keys/GSIs per pattern
- Prefer simpler designs when flexibility matters
Follow-up Questions
- How do overloaded GSIs work?
- When would you NOT use single-table design?
- How do you add a new access pattern later?
References
Continue Learning with AI
Take this question deeper with your favourite AI assistant. Pick a depth, copy the prompt, or open it directly — AI is your learning companion, not a shortcut.
Plain-language foundations
I'm preparing for a software engineering interview and want to understand this from scratch, as a beginner. Topic: DynamoDB (AWS) Interview question: "What is DynamoDB single-table design, and why do experts use it?" Please: 1. Explain the core idea in simple, plain language, using an everyday analogy. 2. Define any technical terms you use. 3. Walk through one small, concrete example. 4. Finish with a single sentence I can easily remember. Keep the tone friendly and assume I'm new to this topic.
Was this answer helpful?
Affiliate links
Tools for Your Developer Workspace
Equipment for a comfortable, productive setup.
As an Amazon Associate I earn from qualifying purchases.
- MonitorView on Amazon : BenQ EW2790U 27-inch Monitor (opens in a new tab)
BenQ EW2790U 27-inch Monitor
- LaptopView on Amazon : Acer Aspire One Laptop (opens in a new tab)
Acer Aspire One Laptop
- Office ChairView on Amazon : Wakefit Gravita Ergonomic Office Chair (opens in a new tab)
Wakefit Gravita Ergonomic Office Chair