12 August 2026 · 7 min read · recloud engineering

DynamoDB: single-table vs multi-table design, honestly

Single-table design has become DynamoDB orthodoxy: cram every entity into one table, overload the keys, and treat conference-talk heroics as best practice. It is genuinely the right call sometimes — and an expensive habit the rest of the time. Having built subscriber stores, order pipelines and session tables both ways, here is the honest ledger.

What single-table actually buys

One thing, mainly — and it's a good thing: related entities in one item collection, fetched in one request. Put a subscriber's profile and their live session under the same partition key and the hot path reads both with a single Query:

PK               SK          attributes
SUB#INH0012345   PROFILE     plan, status, pool
SUB#INH0012345   SESSION     sid, nas, counters, ttl

When that read happens on every subscriber login, saving a round trip is real money and real latency. Secondary benefits are smaller than advertised: fewer tables to alarm on, shared capacity smoothing spiky entities, transactions that co-locate naturally (though TransactWriteItems spans tables anyway, so this one is mostly aesthetic).

What it costs

  • Legibility. PK=SUB#... SK=ORDER#2026-09#... is a bespoke encoding only the design document understands. Every new engineer pays the decoding tax; every debugging session starts with the cheat sheet.
  • GSis become a shared, finite resource. Twenty overloaded access patterns competing for a handful of indexes leads to key gymnastics that make the schema even less readable.
  • Evolution gets scary. Adding an entity means threading it through existing key conventions without colliding. In multi-table land it means… creating a table.
  • Analytics hates it. Exports to Athena or ClickHouse arrive as a soup of heterogeneous items that every query must first untangle.
  • IAM gets coarse. Table-level permissions can't say "the portal may read profiles but not sessions" when both live in one table.

What multi-table costs

Less than the talks imply. The extra reads are parallel BatchGetItem calls, not sequential waterfalls — single-digit milliseconds side by side. Transactions still work across tables. The genuine loss is the item-collection query: if your hot path truly assembles three entities per request at high volume, multi-table makes you pay for it on every call.

The decision rule that survives production

Ask one question per bounded context: is there a high-volume request that must read multiple entity types together?

  • Yes — subscriber + session on every RADIUS authorization, cart + items on every checkout: give that context a small, documented single table. (Our RADIUS REST backend is exactly this shape.)
  • No — orders here, invoices there, each read by its own service at its own pace: use a table per entity and enjoy schemas a new hire reads in one sitting.

Note the phrase per bounded context. The mature pattern isn't one mega-table for the company; it's a handful of small single-tables where item collections earn their keep, and plain tables everywhere else. Single-table design is a performance optimisation — apply it where the performance exists to optimise.

Need a hand with this in production?

recloud is a group of software and network engineers specialising in Cisco Systems and Juniper, working with Australian ISPs, network operators and enterprises. See backend engineering, custom RADIUS backends. Or contact us.