SQL vs NoSQL
Theme
Palette
Download
Caption (tap to copy)
📖 Deep dive (full written explanation)
This series spends a full day on SQL vs NoSQL because the choice between them is one of the highest-leverage architecture decisions you make early in a project, and one of the hardest to reverse. The framing in this post deliberately rejects the lazy 'old vs new' narrative. Both model families are actively developed, widely used, and correct for different jobs.
The goal of post one is purely conceptual: by the end you should be able to say what 'relational' actually means, name the four NoSQL families, and articulate the single trade-off — fixed structure versus flexible structure — that everything else flows from.
A relational database is defined by three things: data lives in tables of rows and columns, each table has a fixed schema declaring its columns and their types, and tables connect to each other through keys. The schema is enforced by the engine, not by your application, which is what makes it 'schema-on-write' — the database refuses to store a row that violates the rules.
SQL, the Structured Query Language, is declarative: you describe what you want, not how to fetch it. The engine's query planner figures out the how. This separation is why a well-indexed relational database can answer questions its designers never anticipated, just by writing a new query.
'NoSQL' is a marketing umbrella, not a coherent technology. The name originally meant 'non-relational' and later softened to 'not only SQL.' What unites these systems is a willingness to drop the rigid table-and-schema model in exchange for flexibility, scale, or a specialized data shape.
The most important thing to internalize is that the four families underneath are radically different from each other — a key-value store and a graph database have almost nothing in common. Saying 'we'll use NoSQL' is about as specific as saying 'we'll use a vehicle.' You have to name the family.
The four families each optimize a different access pattern. Document stores like MongoDB keep self-contained JSON-like documents and suit data read as a unit. Key-value stores like Redis are a giant distributed dictionary — blazing fast for 'get the value for this key,' useless for anything else. Wide-column stores like Cassandra handle enormous write volumes with rows that can have millions of dynamic columns. Graph databases like Neo4j make relationships first-class, ideal for social networks or recommendation engines.
Knowing the families lets you skip the false 'SQL or NoSQL' binary and ask the real question: which specific store matches my data's shape and access pattern.
Schema-on-write versus schema-on-read is the cleanest way to capture the core trade-off. In SQL, structure is defined and validated when you write, so every row that lands in the table is guaranteed to conform. The cost is that changing the shape requires a migration.
NoSQL typically defers structure to read time: you can store whatever shape you want, and the application decides how to interpret it later. The benefit is effortless evolution — add a field, ship it. The cost is that the database no longer protects you; correctness becomes your code's job, and old and new shapes coexist until you handle them.
This slide corrects the most common misreading of the word 'relational.' It does not mean the data is loosely 'related.' It refers to the relational model from set theory, where relationships between tables are expressed through keys: a primary key uniquely identifies a row, and a foreign key in another table points back to it.
The practical payoff is normalization — each fact is stored exactly once. A user's email lives in one row; everything else references that user by id. When the email changes, you update one place and every query sees the new value. Joins reassemble the normalized pieces on demand, trading a little query-time work for guaranteed consistency.
The tree diagram is the mental hierarchy to carry forward. At the top, databases split into relational and non-relational. The relational branch is relatively uniform — Postgres, MySQL, SQL Server, and others all share the table-and-SQL model with minor dialect differences.
The NoSQL branch immediately fans into the four families, and that fan-out is the whole point. When someone asks 'should we use NoSQL,' the correct response is another question: which family, and why. The tree keeps you from collapsing four very different tools into one fuzzy label.
These two code slides make the abstract concrete with the smallest possible example. The SQL version declares a table with explicit columns, a primary key, a NOT NULL constraint, and a UNIQUE constraint on email. The database will now reject any insert that omits a name or duplicates an email — correctness is enforced at the storage layer before your application ever sees a problem.
Notice how much the schema communicates: anyone reading this DDL knows exactly what a user looks like. That self-documenting structure is a real, underrated benefit of relational design.
The document version stores the same user as a single flexible object. There's no separate schema declaration — the shape is implied by the data you insert. The 'tags' array shows the flexibility advantage: you can attach new fields to one document without touching any others or running a migration.
That freedom is exactly what makes document stores pleasant for rapidly evolving data and dangerous for data that must stay consistent. Nothing stops a second document from spelling the field 'e-mail' or omitting it entirely. The structure you didn't declare is structure your code now has to assume.
The historical context explains why two such different models coexist. The relational model dates to the 1970s, designed when disk was expensive and the priority was eliminating redundancy and guaranteeing consistency on a single machine. ACID transactions were the crown jewel.
NoSQL emerged in the late 2000s from companies like Google (Bigtable) and Amazon (Dynamo) facing a different reality: billions of operations across thousands of commodity servers, where strict consistency and cross-machine joins were too slow or simply impossible. They traded some guarantees for scale and availability. Neither side 'won' — they solved different problems, and both problems still exist.
The closing tips compress the whole decision into a checklist you can actually use. The throughline: relational is the right default for most applications because most application data is relational and most applications never reach the scale where NoSQL's trade-offs pay off.
The questions to ask are concrete. Is the data full of relationships you'll query across? Do you need atomic transactions? Then SQL. Are fields constantly changing, are writes huge and simple, do you have a single known access pattern at massive scale? Then a specific NoSQL family. The mistake is choosing by fashion instead of by these questions.
Post one set the conceptual map: what relational means, the four NoSQL families, and schema-on-write versus schema-on-read. With that foundation, the comparison stops being a vibe and becomes a set of trade-offs you can reason about.
Post two turns to stakes: why this choice is worth getting right. We'll cover how the model affects data correctness, the CAP theorem's forced trade between consistency and availability, the deep difference between scaling up and scaling out, and the very real costs of picking the wrong shape.