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.
โCoffee Chat Question
Concept Made Simple
โWhat is DynamoDB single-table design, and why do experts use it?โ
๐ง Mind Map Answer
Remember It Faster
| 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.
โจ๏ธHands-on Keyboard
Learn by Doing
// 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.
๐ฅWhat If?
Think Beyond the Expected
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:
โ ๏ธ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
- 1How do overloaded GSIs work?
- 2When would you NOT use single-table design?
- 3How do you add a new access pattern later?
๐งฉRelated Technologies
๐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?
โญ Featured Products
Support our platform by exploring our recommended products.
As an Amazon affiliate, purchases through these links may earn us a small commission โ at no extra cost to you. It helps keep Full Stack Interview Guru free.