Offload read traffic to synchronized copies of the primary database.
If you are new here: A read replica is a read-only copy of your database that follows the primary by replaying its log of changes. You send writes to one leader; you spread reads across replicas — with lag as the trade-off.
| Traffic type | Usually routed to |
|---|---|
INSERT / UPDATE / DELETE | Primary |
| Heavy reporting, fan-out reads | Replicas |
| “Just wrote, must read back” | Primary (or app-level rule) |
| Term | Plain meaning |
|---|---|
| Primary / leader | The writable database that accepts INSERT/UPDATE/DELETE |
| Replica / standby | A read-only copy that follows the leader’s change log |
| Replication lag | How far behind a replica is — stale reads are normal |
| Read-after-write | User flow where the next read must see the just-written row |
Your single primary serves every transaction and every report. Transactional (OLTP) traffic and heavy SELECT analytics fight for the same CPU and connections. Checkout queries and nightly BI exports share one connection pool; a slow report can still block resources the payment path needs.
In plain terms: read replicas are photocopies of your database that can answer SELECT — so the writer stops being the only place every read goes.
Analogy: A busy store with one cashier for returns and catalog questions turns into chaos. Replicas are extra staff who can answer questions (reads) but cannot change inventory (writes) — unless you promote one, which is a different (risky) story.
Read replicas add read-only copies fed by the replication log — trading operational complexity and eventual reads for horizontal read capacity.
That is the problem this lesson exists to solve: scale reads and protect the primary without pretending replicas are magic extra writers.
The primary has two jobs: accept writes and answer reads. Heavy dashboards, exports, search screens, and admin reports can consume the same CPU, memory, I/O, and connection slots needed by checkout or login.
Tiny example: A nightly report runs a 90-second aggregate query on the primary while checkout traffic peaks. Even if the report is “just a SELECT,” it can evict cache pages, hold connections, and make critical reads slower.
Read replicas give you a place to move read-heavy or stale-tolerant work so the primary can focus on writes and correctness-sensitive reads.
The primary applies commits; standbys replay the write-ahead log (WAL — the database's sequential record of every change, like a redo journal) asynchronously. They are not extra primaries — writes still funnel to one leader (in the usual pattern).
Analogy: The primary is the authoritative textbook; replicas are photocopies that get new pages faxed over — usually fast, but not instant.
Replicas are normally read-only. That is a feature, not a limitation: it keeps one clear write authority and avoids conflicts. Promotion during failover is a separate operation where a replica becomes the new primary.
Applications or proxies route INSERT/UPDATE/DELETE to the leader and balance SELECT across replicas — often with health and lag awareness.
Pseudo-config idea: “Reporting service uses replica.internal; checkout service uses primary.internal for payment rows.”
In plain terms: not all reads are equal. A product catalog page can probably read from a replica. The page shown immediately after “save profile” should probably read from primary for a short window.
Many apps encode this as routing rules: writes and read-after-write flows use primary; analytics, dashboards, and cache fills use replicas.
Replicas trail the primary. A few milliseconds is normal; spikes happen under load or network issues — monitor replication lag like an SLO.
Lag means the replica is correct eventually, not necessarily right now. Under write bursts, long-running replica queries, or network trouble, lag can grow from milliseconds to seconds or minutes.
Operator metric: alert on lag in time and bytes, and remove lagging replicas from latency-sensitive read pools. A slow replica serving stale checkout reads is worse than no replica.
After I post a comment, my next GET might hit a replica that has not applied that write yet — looks like data loss. Mitigations: read-after-write to primary, session stickiness, or client hints.
| Pattern | Mitigation |
|---|---|
| User creates resource, immediately lists | Route that read to primary briefly |
| Global analytics dashboard | Replicas OK; label “~1 min delay” |
The UX problem is trust. A user who posts a comment and cannot see it assumes data was lost, even if the replica catches up 400 ms later.
Common mitigations include sticky “read my writes” sessions, primary reads for a few seconds after writes, client-side optimistic display, or explicit freshness labels for dashboards.
| Replicas are good for | Be careful with |
|---|---|
| Reporting and BI reads | Read-after-write flows |
| Offloading cache fills | Replica lag under write bursts |
| Safer heavy ad hoc queries | Failover and promotion runbooks |
| Geographic read latency | Cross-region consistency expectations |
Replicas scale reads, not writes. If the primary is write-bound, you need different techniques: batching, schema changes, partitioning, sharding, or moving write-heavy features elsewhere.
Replicas are cheap read scale and great for reporting — but correctness-sensitive flows need a plan for your writes, your reads until BASE semantics are acceptable.
Next: Data Replication covers the mechanics — synchronous vs asynchronous replication and what multi-leader setups mean for conflict resolution.
A single primary is simple — until reporting, exports, and product growth make reads compete with writes.