Using more than one, and keeping them in step
The scenarios lesson kept reaching the same shape: PostgreSQL for the truth, plus a specialised store for one job. That shape has a name — polyglot persistence, using more than one kind of database in a single application, each for what it does best. This lesson is how to do it well, because the benefit is real and so is the way it goes wrong.
What it is, and why it is normal
Almost every non-trivial production system is already polyglot:
PostgreSQL — users, orders, products, payments (the source of truth)
Redis — sessions, cache, rate limits (the fast layer)
Elasticsearch— product search (the search index)
S3 / blob — images, uploads, files (large binary objects)
That is four stores, and it is an ordinary, healthy architecture — not a failure of design. Different data has genuinely different needs, and forcing all of it into one store means forcing some of it into a poor fit. Using the right tool per need is maturity, not sprawl.
The distinction that separates healthy polyglot from a mess is deliberate versus accidental. "We added Redis because sessions belong in a fast expiring store, and here is how it stays correct" is engineering. "We have six databases because each new feature reached for whatever was trendy that quarter" is the mess. Same count of systems; completely different situation.
The architecture that keeps it sane
One principle prevents most polyglot pain:
Designate a single source of truth, and treat every other store as a derived, disposable copy.
- PostgreSQL owns the truth. Users, orders, the authoritative data — it lives in one place, with ACID and constraints protecting it.
- Every other store is derived from it and rebuildable. The Redis cache, the Elasticsearch index, a materialised rollup — all can be reconstructed from PostgreSQL if lost. None holds data that exists nowhere else.
Apply the test from the caching module to the whole architecture: if any non-source-of-truth store vanished, the application should get slower or lose a feature — never lose data. If losing a store would lose data, that store has quietly become a source of truth and needs the durability and care of one. Knowing which stores are authoritative and which are derived is the single most important thing to be clear about in a polyglot system.
The hard part: keeping them in step
Multiple stores mean multiple copies, and copies drift. This is the central challenge, and there are three ways to handle the sync, worst to best.
Dual writes from application code — the tempting trap.
db.save(order) # write to PostgreSQL
search.index(order) # and to Elasticsearch
cache.set(order) # and to Redis
This looks obvious and is the most common way polyglot systems go wrong, because these writes are not atomic. The process can die after the first and before the others, or the search write can fail while the database write succeeded — and now the stores disagree with no record of it. There is no transaction spanning PostgreSQL and Elasticsearch. Avoid dual writes for anything that matters.
Asynchronous propagation — the robust pattern. Write to the source of truth only, and let the derived stores update from a reliable stream of changes:
- Change Data Capture (CDC) — a tool (Debezium is the standard) reads PostgreSQL's write-ahead log and emits every change as an event; the search indexer and cache updater consume that stream. The database write is the single source of the change, so the copies cannot miss one.
- The transactional outbox — write the business change and an "outbox" row in the same PostgreSQL transaction; a separate process reads the outbox and propagates to the other stores. Because the outbox write is atomic with the business write, you never lose an event, and the propagation can retry until it succeeds.
Both share the key property dual writes lack: the change is committed once, atomically, in the source of truth, and the derived stores catch up reliably from there. They are eventually consistent by design — the search index lags the database by a moment — which is exactly the staleness the earlier modules taught you to accept and bound.
Rebuild from source. Because the derived stores are disposable, you can always drop and rebuild them from PostgreSQL — reindex Elasticsearch, warm the cache. This is your recovery path when a derived store is corrupted or a sync falls behind, and it is only possible because you kept a clear source of truth.
The costs, stated plainly
Polyglot persistence is powerful and not free — weigh the same costs from the last lesson, multiplied:
- Operational load per store — running, backups, monitoring, security, expertise — times the number of stores, plus the sync machinery between them.
- Eventual consistency to reason about — the search index and cache lag the truth, and your code and your users must tolerate that window.
- More failure modes — one store down while another is up; a sync falling behind; a rebuild mid-flight. The interactions are where the subtle production bugs live.
- Cognitive load — every engineer must know which store owns what, and how they relate.
So the counsel is the same as everywhere in this course, applied to architecture: start with PostgreSQL alone. Add each store deliberately, when a specific need justifies its full cost, with a clear sync strategy and a clear understanding of what is truth and what is derived. Do not begin polyglot; grow into it, one justified store at a time.
Check your work
What polyglot persistence is. Using more than one kind of database in one application, each for what it does best.
Why it is normal, not a failure. Different data has genuinely different needs; the right tool per need is maturity.
Healthy versus messy polyglot. Deliberate, justified additions with a sync strategy — versus accidental accumulation of trendy stores.
The organising principle. One source of truth (PostgreSQL); every other store derived and disposable.
The whole-architecture test. If a non-source-of-truth store vanished, the app gets slower or loses a feature — never loses data.
When a derived store has secretly become a source of truth. When losing it would lose data — then it needs a source of truth's durability.
Why dual writes from app code are a trap. The writes are not atomic; a crash or a partial failure leaves the stores disagreeing with no record.
The two robust sync patterns. Change Data Capture (read the WAL, emit change events) and the transactional outbox (write the change and an outbox row in one transaction, propagate from it).
What both share. The change commits once atomically in the source of truth; derived stores catch up reliably and eventually.
Why rebuild-from-source is possible. The derived stores are disposable copies of a clear source of truth.
The costs. Operational load per store times the count, plus sync; eventual consistency; more failure modes; cognitive load.
The counsel. Start with PostgreSQL alone; grow into polyglot one justified store at a time.
Practice
- Diagram a real application's stores and label each as source-of-truth or derived.
- Apply the vanish test to each derived store: what breaks, and does any data disappear?
- Find a store you labelled "derived" that would actually lose data if gone. Decide how to fix that.
- Write the dual-write version of "save an order and index it for search", then describe the exact crash that leaves them inconsistent.
- Redesign it with a transactional outbox. Show why the outbox write cannot be lost.
- Describe how CDC would keep an Elasticsearch index in sync with PostgreSQL, and where it can lag.
- Write the rebuild procedure for a derived store from the source of truth.
- Estimate the full operational cost of one real polyglot architecture, and decide whether each store earns its place.
Official documentation
- Martin Fowler — Polyglot persistence — The idea and its motivation.
- Debezium — Change Data Capture — Streaming PostgreSQL changes to derived stores.
- Transactional outbox pattern — The atomic-with-the-business-write sync pattern.
- PostgreSQL — Logical replication — The mechanism CDC tools build on.
- AWS — Database caching strategies — Keeping a derived cache in step with the source.
Next: what it costs to change your mind.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship