Blog 5
Data and Databases — From Persistence to SQL, NoSQL, and Source of Truth
Imagine a bank sends out a proud announcement: "We've migrated to a beautiful, modern technology stack."
Then, a day later, a second message: "Unfortunately, in the process, we lost everyone's account balances."
Nobody is impressed by the modern stack anymore.
Part 4 followed a request across the internet — DNS, CDN, load balancer, reverse proxy, application server, cache, and finally the database, which we called the source of truth and left as a promise. This article keeps that promise.
Because here's the thing that bank story makes unavoidable: the system didn't fail because of a bad framework, a slow server, or a clunky deployment pipeline. All of those could have been perfect. The system failed because it lost the one thing that actually mattered — the data.
This is the mindset shift this whole article is built on. Every serious system, if you follow it far enough, becomes a data problem. Code can be rewritten. Servers can be replaced. Caches can be rebuilt from scratch. Frameworks come and go. But if the data is lost, corrupted, inconsistent, or impossible to trust — the system has failed, no matter how elegant everything around it was.
So we're going to build up, from first principles, an understanding of data and the databases that protect it: why data is the most valuable asset in most systems, why persistence exists, why databases were invented at all, how relational databases and ACID give us trust, why NoSQL emerged, and — most importantly — how a good architect actually decides where data should live. Not "SQL or NoSQL?" as a tribal debate, but the real question underneath it.
Let's start with why data deserves this much respect.
Applications Are Temporary. Data Is Long-Lived.
Here's a truth that takes most engineers years to fully feel: the application is the temporary part. It's the data that lasts.
Think about the lifespan of the things in a real system. The UI gets redesigned every couple of years. The backend framework gets swapped when the team's preferences shift. The infrastructure migrates from one platform to another. The deployment pipeline is rebuilt. The code itself is refactored, rewritten, sometimes thrown away entirely and started fresh.
And through all of that churn, one thing quietly survives every rewrite: the users and their accounts, the orders and payments, the messages and conversations, the invoices, documents, and audit logs, the product catalogs and business history.
A company can rebuild its entire application from scratch and survive. It cannot survive losing its customers' transaction history. It cannot afford to lose the audit trail a regulator will ask for. The application is scaffolding around the asset — and the asset is the data.
There's a clean way to hold this: software creates business value. Data preserves it.
The code is how value gets made — orders placed, messages sent, payments processed. But the data is where that value is kept, across every version of the software that will ever run. Once you internalize that applications are temporary and data is long-lived, your priorities as a designer quietly reorder themselves. You start protecting the right thing.
What Is Data, Really?
Let's ground the word before we build on it. Data is simply the information a system needs to remember. That's it. But "information a system remembers" comes in strikingly different kinds, and the differences matter enormously for how we store it:
- User data — names, emails, password hashes, preferences. The record of who uses the system.
- Business data — orders, invoices, transactions, products. The record of what the business did.
- Operational data — logs, metrics, audit trails. The record of how the system behaved.
- Content — images, videos, documents, messages. The things users create and consume.
Now here's the insight that unlocks everything later in this article: different data has different value, lifetime, size, access pattern, and correctness requirements.
A password hash is tiny, rarely changes, and must be exactly right. A video is enormous, never changes once uploaded, and doesn't need transactions. A log entry is small, written constantly, read rarely, and it's fine to expire it after a while. A payment record is small but sacred — it must never be lost, never be wrong, and must be kept for years.
These aren't the same kind of thing, and — spoiler for the whole article — they often don't belong in the same kind of store. Holding onto "different data has different needs" is the seed of every good storage decision we'll make later.
Memory Is Fast, But Forgetful
So a system needs to remember things. The obvious first question: why not just keep it in memory?
A running program can absolutely hold data in memory — it's the fastest storage there is. Reading from RAM is blisteringly quick; reading from the CPU's own cache is quicker still. If speed were the only thing that mattered, we'd keep everything in memory and never think about it again.
But memory has a fatal flaw for anything that matters: it forgets.
The moment the process stops — a crash, a restart, a routine deploy, a power loss, a machine failure — everything in memory simply vanishes. RAM and CPU cache are volatile: they hold data only as long as the power and the process are alive. Pull either, and it's gone, instantly and completely.
That's a catastrophe for anything you actually need to keep. Imagine a bank holding account balances only in memory, and a server reboots. Imagine an e-commerce site holding orders in RAM, and the process crashes mid-day. The speed was wonderful right up until the instant it mattered, and then there was nothing.
So the trade-off is stark and clean: memory is excellent for speed. Memory is terrible for long-term truth.
That single tension — fast but forgetful — is exactly why we need something else. We need data that survives the process that created it. We need persistence.
Persistence: The System's Ability to Remember
Persistence means data survives beyond the process that created it. That's the whole idea, and it's the foundation everything else rests on.
Persistence is what makes these three things true:
Application restarts → Data still exists
Server reboots → Data still exists
Application upgraded → Data still exists
The process that wrote the data can die, restart, be upgraded, or be replaced entirely — and the data is still there, waiting, correct, on durable storage (a disk, a solid-state drive, a managed storage service) that doesn't forget when the power blinks.
Without persistence, there's no system worth speaking of. Every restart would wipe the users. Every deploy would erase the orders. Every crash would lose the messages, the payments, the business history. The entire point of most software — to remember something reliably — would be impossible.
Persistence is the quiet capability that turns a program that computes into a system that remembers. And once a system needs to remember reliably, we have to ask a deeper question about its very nature: does it hold state at all, and where?
Stateless vs Stateful Systems
This distinction runs through all of system design, and it connects straight back to Part 4. Some parts of a system remember things between requests. Some deliberately don't. Both are useful, for opposite reasons.
A stateless system remembers nothing between requests. Each request arrives, gets processed, gets a response, and then the system forgets it ever happened:
Stateless Service
Request → Process → Respond → Forget
Because it holds no state, a stateless service is wonderfully easy to work with: easy to scale (just add more identical copies — none of them needs to know what the others did), easy to replace (kill one, start another, no loss), and easy to deploy (nothing to preserve across the swap).
A stateful system, by contrast, remembers — it holds information that persists across requests and preserves ongoing business workflows:
Stateful System
Request → Process → Store / Update State → Remember
That memory is essential — it's what preserves the actual business value — but it comes at a cost. Stateful systems are harder to scale (the copies must somehow agree on the shared state), harder to replicate, and harder to recover after failure.
Here's where it ties back to the request journey from Part 4. Remember how the application servers sat behind a load balancer, easily added and removed? That works precisely because they're usually designed to be stateless — any server can handle any request, so scaling is trivial. And remember how the database was the carefully-protected source of truth? That's because the database is where the state deliberately lives.
This is a foundational architectural pattern you'll see everywhere: push state down into a few carefully-managed stateful components (databases), and keep everything above them stateless so it can scale freely. The statelessness of the app tier and the statefulness of the database aren't accidents — they're a deliberate division of labor. And that stateful layer is exactly what we need to build well. Which raises the question: how do we store state reliably? For a long time, the answer was simply "files."
Why Files Were Not Enough
Before databases, storing data was straightforward: you wrote it to a file. Text files, CSVs, JSON, XML — durable, simple, and honestly fine for a small system with one user and modest data. Plenty of useful software has been built on exactly this.
Then the system grows, and the cracks appear one by one: multiple users show up at once, all wanting the same data; concurrent writes collide — two processes editing the same file, corrupting each other; search performance collapses — finding one record means scanning the entire file; data corruption creeps in when a write is interrupted halfway; partial updates leave the file in a broken, half-written state; access control is crude — a file is readable or it isn't, there's no "this user can see these rows"; recovery after a crash is a nightmare — was the last write finished or not?; and query flexibility is nonexistent — you get whatever structure you hard-coded, nothing more.
None of this means files are bad. Files are a perfectly good tool — your operating system runs on them, and object storage (which we'll meet later in the series) is essentially files done at massive scale. The point is narrower and more honest: files aren't bad. They're just not enough for many multi-user, concurrent, growing systems.
The moment you have many users, simultaneous writes, a need to search efficiently, and a requirement that data never corrupt — raw files start fighting you at every turn. Something purpose-built was needed. That something is the database.
Why Databases Were Invented
Databases exist to solve, all at once, the exact problems that make raw files painful at scale. A database is a system purpose-built to handle: persistence (data survives crashes and restarts, as we've discussed), concurrency (many users can read and write safely at the same time without corrupting each other), querying (you can ask rich questions — "all orders over $100 from last week" — instead of scanning everything), indexing (those queries can be fast even over huge datasets), consistency (the data stays valid according to your rules), transactions (groups of changes happen all-or-nothing, more on this shortly), recovery (after a failure, the database can restore itself to a correct state), and security and access control (fine-grained rules about who can see and change what).
Look at that list against the list of file problems just above. It's almost a point-by-point answer. That's not a coincidence — it's why the category exists.
Databases weren't invented because files were useless. They were invented because scale, concurrency, and correctness made raw files painful.
That framing matters, because it tells you what a database is: not a magic box for storing things, but a carefully engineered solution to the specific problems of remembering data safely when many users, high volume, and strict correctness are all in play at once. Now, before we look at the databases themselves, we need to notice that the data they store doesn't all look the same.
Not All Data Looks the Same
Remember the earlier point that different data has different needs? Here's where it becomes concrete. Data comes in three broad shapes, and the shape strongly influences where it should live:
Structured data has a predictable, rigid schema — neat rows and columns, every record the same shape: users, orders, payments, inventory. Think of a spreadsheet: defined columns, one row per record.
Semi-structured data has flexible fields — it has some structure, but records can vary, and the shape can evolve: JSON-like documents, profiles, settings, metadata. Think of a folder of forms where each form can have slightly different fields.
Unstructured data has no queryable internal structure at all — it's just content, usually large: images, videos, audio, PDFs, documents. Think of a media library: the system stores and serves the file, but doesn't query inside it.
Why does this matter so much? Because different data shapes lead to different storage choices. Structured transactional data thrives in a relational database. Flexible, evolving records often fit a document store. Huge binary files belong in object storage, not a database at all. The shape of your data is one of the first and strongest signals for where it should live — a thread we'll pull all the way through this article.
The Most Important Concept: Source of Truth
If you take one idea from this entire article, make it this one. As systems grow, data doesn't stay in one place — it gets copied, deliberately, for all sorts of good reasons:
Primary Database
↓
Cache (a fast copy, for speed)
↓
Search Index (a searchable copy)
↓
Analytics Store (a copy shaped for analysis)
↓
Reports (a summarized copy)
Now every one of those copies can answer questions. So a dangerous question arises: when they disagree — and eventually they will — which copy do you trust?
The answer must be decided deliberately, in advance, and it has a name: the source of truth. The source of truth is the one authoritative place where data is considered definitively correct. Everything else is a derived copy — a copy that exists for performance, search, analytics, reporting, or user experience, but is not the authority. When a derived copy disagrees with the source of truth, the source of truth wins, always, and the derived copy is the one that's wrong and must be corrected.
In practice: the product database is the source of truth; the search index is derived from it. The order database is the source of truth; the dashboard is derived. The payment ledger is the source of truth; the monthly report is derived. The document's operation log is the source of truth; a snapshot of the document is derived.
Here's why this concept is load-bearing for everything ahead: every serious system must know what is its source of truth and what is merely derived. Get this clear, and caches, search indexes, and analytics stores all become safe, powerful tools — you always know which copy is authoritative. Get it unclear, and you've built a system where nobody knows which version of the data is real, and correctness quietly falls apart. Hold this thought especially tightly — it's the exact reason caching, in the next article, is safe rather than dangerous.
With data understood — its value, its shapes, its truth — we can finally look at the databases that store it, starting with the family that has anchored serious systems for decades.
Relational Databases: Structure, Relationships, and Trust
The relational database has been the backbone of serious software for decades, and for good reason. It organizes data into a clean, disciplined structure: tables (one per kind of thing — a Users table, an Orders table), rows (one per record — one user, one order), columns (the defined fields every row has — name, email, created_at), and relationships (links between tables that connect related data).
That last one — relationships — is the heart of the "relational" name. Consider a simple example: a Users table and an Orders table. Each order needs to know which user placed it, so it references the user:
Users.UserId
↓ (referenced by)
Orders.UserId
Every order carries the UserId of the user who placed it, creating a relationship between the two tables. Now you can ask rich questions across them — "all orders by this user," "the user behind this order" — and the database enforces that the link stays valid.
This model became popular because it delivers a rare combination of qualities that serious business systems crave: clear structure (you know exactly what shape every record has), predictable schema (the rules are defined and enforced), relationships (related data is genuinely connected, not just loosely associated), a powerful query language — SQL (you can ask complex questions declaratively), transactions (groups of changes succeed or fail together, next section), and integrity constraints (the database refuses to store data that breaks your rules).
You've likely used one — PostgreSQL, MySQL, Oracle, SQL Server are all relational databases. We won't compare them vendor by vendor; that's not the point. The point is why this whole family earns trust for important data. And the deepest part of that answer is a four-letter idea: ACID.
ACID: Why Some Systems Trust SQL Databases
ACID is the set of guarantees that makes relational databases trustworthy for data that must never be wrong. The cleanest way to understand it is a money transfer — moving $100 from Alice to Bob. That single action is really two changes: subtract $100 from Alice, add $100 to Bob. ACID is about making sure those two changes behave correctly no matter what goes wrong.
Atomicity — all or nothing. Both the debit and the credit happen, or neither does. There is no universe where $100 leaves Alice's account but never arrives in Bob's. If the system crashes right between the two steps, atomicity guarantees the whole thing is rolled back as if it never started. Money is never created or destroyed by a half-finished transfer.
Consistency — the rules stay true. The transfer can't leave the database in a state that violates its rules. If there's a rule that balances can't go negative, a transfer that would break it is rejected, not allowed through. The database moves from one valid state to another valid state, never landing somewhere invalid.
Isolation — transactions don't corrupt each other. If a thousand transfers happen at the same instant, each behaves as though it ran alone. Two simultaneous transfers touching Alice's account won't interleave and produce a garbled balance. Concurrency doesn't mean chaos.
Durability — committed means permanent. Once the transfer is confirmed, it survives — a crash, a power loss, a reboot a second later won't undo it. Committed data is written to durable storage and stays written.
Put those four together and you have a system you can genuinely trust with data where being wrong is unacceptable. That's precisely why relational databases dominate in banking and payments, orders and inventory, ERP/HRMS/financial systems, and anywhere correctness is non-negotiable.
When "the number must be exactly right, always, even through failures," ACID is the guarantee that makes it possible. This is the concrete meaning of a phrase you'll hear constantly: SQL databases are strong where correctness matters most. But powerful as they are, relational databases weren't the perfect fit for every problem the internet threw at them.
Why SQL Alone Was Not Enough for Every Internet System
Relational databases are powerful and trustworthy — so why did an entire new category of databases emerge? Not because SQL got worse. Because the problems changed.
As systems went from serving thousands of users to serving hundreds of millions globally, new pressures appeared that the classic relational model wasn't originally designed for: massive write volume (millions of writes per second, far beyond a single database's comfort), flexible, evolving schemas (data whose shape changes constantly, where a rigid predefined schema becomes a straitjacket), global distribution (data that must live in many regions at once, close to users everywhere), huge event streams (endless firehoses of append-only data — clicks, logs, sensor readings), extreme availability needs (systems that must never go down, even during failures), enormous datasets (data far too large to fit on any single machine), and simple key-based access at massive scale ("give me the value for this key," billions of times, as fast as possible).
The traditional relational database, with its strong guarantees and single-node roots, could be stretched to handle some of this — but stretching it was expensive and awkward. And crucially: this does not mean SQL became bad. It means new data shapes and access patterns needed new storage models.
That's the honest framing, and it's the opposite of how this often gets discussed. The internet didn't outgrow relational databases; it grew additional needs that relational databases weren't the ideal tool for. New problems called for new tools — and those new tools got grouped under a confusing umbrella term: NoSQL.
NoSQL: Not One Thing, But Many Storage Models
Here's the first thing to understand about NoSQL, because the name misleads almost everyone: NoSQL is not a single type of database. It's not "the database that isn't SQL." It's a family of different storage models, each designed for a particular data shape and access pattern. Lumping them together is like lumping "all vehicles that aren't sedans" — trucks, motorcycles, and bicycles have very little in common.
There are four major families, and knowing what each is for is far more useful than memorizing names:
| Family | What it stores | Great for | Weakness |
|---|---|---|---|
| Document databases | JSON-like documents, flexible schema per document | User profiles, content metadata, catalogs, evolving data | Complex relationships across documents are harder than in a relational database |
| Key-value stores | A key mapped to a value — a giant dictionary | Sessions, caching-style access, simple lookups, configuration | Limited querying — built for lookup by key, not "all values where X" |
| Wide-column stores | Flexible columns across many machines | Event logs, time-ordered data, massive write-heavy workloads | Rewards knowing your query patterns up front; punishes ad-hoc queries |
| Graph databases | Entities and the relationships between them | Social graphs, fraud detection, recommendation relationships | Not general-purpose — awkward outside relationship-heavy problems |
Document Databases
Store data as JSON-like documents with flexible schema — each document can have its own shape, and that shape can evolve freely.
Key-Value Stores
The simplest model: a key maps to a value, like a giant dictionary. Ask for a key, get its value, extremely fast.
Wide-Column Stores
Designed for huge distributed datasets and very high write throughput, organizing data into flexible columns across many machines.
Graph Databases
Optimized for relationships themselves — where the connections between things are as important as the things.
Notice the pattern across all four: each is excellent at a specific shape of data and access, and weaker elsewhere. There's no "best NoSQL database" any more than there's a best tool in a toolbox. Which leads us straight to the debate that this whole article has been quietly dismantling.
SQL vs NoSQL Is the Wrong Debate
Teams argue about this endlessly and emotionally — PostgreSQL versus MongoDB, relational versus document, SQL versus NoSQL — as though one side must be right. But the entire framing is wrong. The question was never "which is better?" The question is always: "what does this data need?"
Once you ask that question, the answer usually chooses itself. Banking and payments need strong consistency, transactions, auditability — this is ACID's home turf, a relational/ledger-style system fits naturally. Social profiles need flexible schema, enormous scale, simple access patterns — a document or key-value store often fits better than forcing it into rigid tables. A catalog with search has its source of truth in a database (probably relational), while the search index is a derived copy in a search-optimized store — both, each for its job. Analytics and events are append-heavy floods of data, pointing toward warehouses, event stores, or time-series systems designed for exactly that.
Look closely at the third and fourth examples — they don't pick one database at all. They use several, each for the part of the problem it's best at. That's the real revelation: modern systems often use multiple stores at once. A single application might keep its transactional data in a relational database (source of truth), its sessions in a key-value store, its search in a search index, and its analytics in a warehouse — each chosen because it fits that data's shape, access pattern, and correctness needs. The relational database being the source of truth while a search index is derived is exactly the source-of-truth concept in action.
This practice of deliberately using multiple specialized stores has a name — polyglot persistence — and it gets a dedicated deep dive later in the series. For now, the mindset is what matters: stop asking "SQL or NoSQL?" and start asking "what does each piece of my data actually need?" The debate dissolves the moment you do.
Replication, Sharding, and Indexing — The First Scaling Tools
Once your data lives in a database, and that database starts to face real load, three fundamental tools appear again and again. You don't need to master them here — but you should recognize them, because they're the first things reached for when a database is under pressure.
Replication — copies for safety and read scaling
Replication means keeping copies of your data on multiple nodes. If one node dies, another has the data. Its benefits: availability (one node failing doesn't take the data down), disaster recovery (a copy survives even if a whole machine is lost), and read scaling (reads can be spread across the copies, so more readers can be served).
There's a catch, though, and it's a big enough topic to get its own treatment later: keeping copies in sync takes time, which introduces replication lag and raises consistency questions (if you read from a copy, is it fully up to date?). We'll flag that here and return to it in depth.
Sharding — splitting data to grow
Replication copies your data; sharding splits it. When there's too much data for one machine, you partition it across several — each shard holds a slice of the whole. Its benefits: handling more data than any single machine could hold, and distributing load across many nodes instead of concentrating it.
Sharding introduces its own hard question — how do you split the data (the shard key), and how do you avoid "hotspots" where one shard gets all the traffic? That, too, is a deeper topic reserved for later.
Indexing — trading storage for speed
An index is a data structure that makes reads faster — think of the index at the back of a book. Without it, finding a topic means reading every page; with it, you jump straight to the right page. A database index does the same for your data: instead of scanning every row, the database jumps straight to the matching ones.
But indexes aren't free — and this is a clean example of the trade-offs Part 2 promised are everywhere: faster reads (queries that use the index are dramatically quicker), but more storage (the index itself takes space), and slower writes (every write must now also update the index).
So you index the things you search by often, and you don't index everything, because each index taxes every write. Faster reads, in exchange for more storage and slower writes — a deliberate trade, made per use case.
These three — replication, sharding, indexing — are the starter kit of database scaling. We're only introducing them here; each opens into deeper territory the series explores later. The point for now is simply to recognize them as the first tools you reach for when a database meets scale.
CAP, Briefly Revisited
Part 2 introduced CAP as a practical warning, and databases are exactly where it comes home to roost. Once a database is distributed — spread across multiple nodes or regions, via the replication and sharding we just met — CAP stops being abstract.
Here's the short version, grounded in what we now know. When a distributed database spans multiple nodes, and the network between them breaks (a partition), the database is forced into an uncomfortable choice: during that partition, it can favor consistency (refuse operations that might return wrong or divergent data) or availability (keep serving, and risk that different nodes temporarily disagree). It cannot fully have both while the network is broken. That's CAP, and it's a real, unavoidable choice that distributed databases make.
But CAP is useful and incomplete, and it's worth being honest about that. CAP only describes what happens during a partition — the relatively rare case when the network actually breaks. It says nothing about the everyday trade-off that exists even when everything is perfectly healthy: the constant tension between latency and consistency (waiting for all copies to agree is correct but slower; answering from one copy is faster but possibly stale). There's a refinement called PACELC that extends CAP to cover exactly those normal-operation trade-offs, and the series gives it a proper treatment later. For now, just hold CAP as your intuition for the failure case, and know that the fuller picture — the everyday latency-versus-consistency dial — is coming.
How Architects Choose a Database
We've arrived at the practical payoff. After all of this, how does a good architect actually decide where data should live? Not by preference, not by trend, not by which database was on the conference talk last month — but by working through a checklist of what the data genuinely needs:
- What is the shape of the data? Structured, semi-structured, or unstructured?
- What are the main access patterns? By key? By complex query? By relationship? By search?
- What must be strongly consistent? Which data must be exactly right, always?
- What can be eventually consistent? Which data can be briefly stale without harm?
- Is the workload read-heavy or write-heavy? (Part 3's estimation question, returning.)
- How much will the data grow? Gigabytes, or petabytes?
- Do we need transactions? Multi-step, all-or-nothing correctness?
- Do we need flexible schema? Will the shape change often?
- Do we need relationships? Is connected data central to the problem?
- Do we need search? Full-text, ranked, fuzzy matching?
- What is the team's operational maturity? Can we actually run and maintain this well? (Part 2's organizational trade-off.)
- What is the cost profile? What can we afford, at our scale?
Work through those honestly, and the right storage choice — often choices, plural — tends to reveal itself. The data's shape, its consistency needs, its access patterns, and its scale point you toward the right tool far more reliably than any tribal preference ever could.
The principle to carry out of this whole article: database choice should follow data shape, access pattern, correctness requirement, scale, cost, and team capability — not trends, and not tribal loyalty.
Notice how every item on that checklist is a requirement, not a technology. That's the entire mindset in miniature: you don't start with the database and work backward to justify it. You start with the data's real needs and let them lead you to the database. Which is exactly the lesson that took me years to actually learn.
From My Journey: An Architectural Lesson
Early in an engineering career, it's natural to believe software is mostly about code. That's where the craft feels like it lives — the algorithms, the frameworks, the clever abstractions. The database can feel like a detail, a box you dump things into so the interesting code can run.
Real projects, over enough years, teach the opposite lesson — and they teach it in two parts.
The first part is about time. You watch applications get rewritten. Frameworks come and go. The UI gets redesigned twice. The infrastructure migrates to somewhere new. And through every one of those upheavals, the data just... stays. The same users, the same orders, the same transaction history, flowing untouched from one version of the application to the next. Teams can and do rebuild their entire application — but they cannot afford to lose their users, their orders, their payments, their messages, their audit trails, their business history. You realize, slowly, that you had it backwards: the code you thought was the system was the temporary part, and the data you'd treated as a detail was the thing that actually endured.
The second part is about how teams decide. I watched database discussions happen again and again, and so many of them were oddly emotional — PostgreSQL versus MongoDB, SQL versus NoSQL, relational versus document, managed versus self-hosted — argued with the energy of a sports rivalry. And the good architects, the ones whose systems aged well, almost never entered that fight. They asked a quieter, more powerful question: what is this data, how will it be accessed, what correctness does it require, and what has to be the source of truth? They let the answer to that choose the database, rather than choosing the database and defending it afterward.
Two lessons crystallized, and they're worth stating plainly: applications are temporary. Data is long-lived. And: good architects do not fall in love with databases. They fall in love with understanding requirements.
That second line is really the whole discipline. The engineers who make great data decisions aren't the ones with the strongest opinions about databases. They're the ones with the deepest curiosity about requirements — because they know the requirements, understood honestly, will point to the right storage every time.
Why This Article Matters Before Caching
There's a deliberate reason this article comes right before the one on caching, and it's worth making explicit.
The next article is about caching — one of the most powerful performance tools in all of system design. But caching is only safe if you deeply understand one thing first: the source of truth.
Here's why. A cache is, by definition, a derived copy — a fast, convenient duplicate of data whose real home is somewhere else. And the moment you have a copy, you inherit the hard question we met earlier: when the copy and the original disagree, which one is right? If you don't know where your source of truth lives, caching becomes genuinely dangerous — you can end up serving stale, wrong, or contradictory data with no idea which version to trust. But if you do know your source of truth cold, caching becomes safe and enormously powerful: the cache is a fast copy, the database is the truth, and when in doubt, the truth wins.
That's why we built the foundation first. The next article opens with a sharp question that this one has set up perfectly: if databases are so important and so trustworthy — why don't we just query them for everything?
The answer is speed, cost, and scale — and it leads straight into caching, the art of keeping fast derived copies without ever losing track of the truth.
Key Takeaways
- Data is usually the long-lived asset of a system — applications get rewritten, but users, orders, payments, and history must survive.
- Memory is fast but volatile; it forgets the instant a process stops — great for speed, terrible for long-term truth.
- Persistence is the ability to remember: data that survives beyond the process that created it.
- Stateless systems scale and deploy easily; stateful systems preserve business value but are harder to scale, replicate, and recover — so push state down into databases and keep the layers above stateless.
- Databases were invented because files couldn't handle scale, concurrency, and correctness — they solve persistence, concurrency, querying, consistency, transactions, and recovery together.
- Source of truth is the most important concept: know which store is authoritative and which are derived copies, or correctness quietly falls apart.
- Relational (SQL) databases are strong for structured, related, transactional data — clear schema, relationships, and a powerful query language.
- ACID (atomicity, consistency, isolation, durability) is why SQL databases are trusted where correctness is non-negotiable — banking, payments, orders, inventory.
- NoSQL is not one thing — it's a family (document, key-value, wide-column, graph), each fitting a specific data shape and access pattern.
- "SQL vs NoSQL" is the wrong debate — the real question is "what does this data need?", and modern systems often use multiple stores at once.
- Replication, sharding, and indexing are the first database scaling tools — copies for availability and read scaling, partitions for growth, indexes trading storage and write speed for faster reads.
- Database choice should follow requirements — data shape, access pattern, correctness, scale, cost, and team capability — never trends or tribal loyalty.
What's Next
You now understand what a system is really trying to protect — its data — and the databases that hold it safely. You know what a source of truth is, why ACID matters, why NoSQL is a family rather than a rival, and how to choose based on requirements rather than trends.
Which sets up the perfect question for the next article. Databases are powerful and trustworthy — so why not simply query them for everything, all the time? Because speed, cost, and scale won't allow it. Querying the source of truth for every single read would be too slow, too expensive, and would crush the database under load. The answer is to keep fast, derived copies close to where they're needed — which is exactly what caching is.
Blog 6 — Caching at Scale: The Secret Behind Performance. Now that you understand source of truth, caching will make complete sense — because a cache is a derived copy, and you finally know what that means. The next article covers the cache layers from Part 4, now in depth (browser, CDN, reverse proxy, application, and database caches), cache hits and misses and what they cost, TTL and expiration, invalidation — the genuinely hard part, cache stampedes and stale data, and the cache-aside pattern.
Question for Readers
This article's central idea becomes real the moment you apply it to your own work. So, honestly:
In your current system, what is the real source of truth? Which data could you rebuild from scratch if you lost it — and which data would be catastrophic to lose forever? And have you ever watched a team choose a database because it was popular, rather than because it fit the requirements?
That last one is almost universal.