~11 min
A relational database like PostgreSQL organizes data into tables with a fixed schema, and it earns that structure by giving you two things a lot of designs quietly depend on: joins across tables in a single query, and transactions that touch several rows and either all commit or none do. PostgreSQL keeps those transactions fast under concurrent load with MVCC (multiversion concurrency control): PostgreSQL's own documentation explains that each statement sees a snapshot of the data as it was at a point in time, so reading never blocks writing and writing never blocks reading. That's the mechanism, not a marketing line — it's what lets a relational database serve a mix of readers and writers without one queue stalling behind the other, while still giving every reader a consistent view.
A key-value store like DynamoDB starts from a different bet: you know your access patterns in advance, and you design the table around them rather than normalizing first and querying later. Every item has a partition key, and AWS's own guidance is explicit about what that key controls: its value is hashed to decide which physical partition stores the item, so a well-chosen key spreads requests evenly and a poorly chosen one creates a "hot" partition that throttles under load. In exchange for designing around a known access pattern, a key-value store scales writes across many machines far more easily than a single relational primary can — but it gives up the general-purpose join, and a query that wasn't anticipated at design time is often expensive or impossible without a new index.
The choice, then, isn't "relational is old, NoSQL is modern" — it's which bet fits the requirement you scoped earlier. Reach for a relational database when the data has real relationships you'll query across (a ledger, an inventory system, anything where a transaction must touch multiple rows atomically) and when the write volume fits on a primary you can still scale vertically or shard later. Reach for a key-value store when you have one or two access patterns you can name up front, write volume that a single node genuinely can't hold, and you can live with a secondary index or a cross-partition query being slower or eventually consistent. A URL shortener leans key-value — one access pattern, lookup by code; a ledger leans relational — it needs the transaction guarantee more than it needs horizontal write scale.
Relational — a multi-row ACID transaction is exactly what a relational database's MVCC and transaction support are built to guarantee.