PostgreSQL Read Replicas and Replication Lag for Application Reads
Quick answer
Quick answer: a PostgreSQL read replica receives changes from the primary asynchronously, so it can return slightly stale data. Route reads that tolerate...
Quick answer: a PostgreSQL read replica receives changes from the primary asynchronously, so it can return slightly stale data. Route reads that tolerate delay, such as reports and dashboards, to replicas, and keep reads that must see a user's own recent write on the primary or wait for the replica to catch up. Monitor lag continuously, because it varies with load.
Why Do Read Replicas Fall Behind?
With streaming replication, the primary writes changes to the write-ahead log and sends them to replicas, which replay them in order. In the default asynchronous mode, the primary does not wait for replicas to apply a change before acknowledging a commit. That keeps writes fast, but it means a replica is always some distance behind, usually milliseconds and sometimes much more.
Lag grows for several reasons. A burst of writes can produce more log than a replica can replay, especially on slower disks. Network congestion delays delivery. Large transactions, bulk loads, and index builds create heavy replay work. Replay is also mostly single-threaded per replica, so a replica can fall behind even when it has spare CPU.
Long queries on the replica can cause another kind of delay. When a query needs old row versions that replay wants to remove, the replica must either pause replay or cancel the query, depending on settings such as the maximum standby delay. Check the documentation for how your version handles these recovery conflicts.
Which Reads Are Safe to Send to a Replica?
The question to ask is whether the user or process would notice stale data. Many reads tolerate a delay of a second or more without anyone caring, and moving them frees the primary for writes:
- Analytics, reports, and dashboards that summarize large amounts of history.
- Search pages, listings, and catalog browsing where freshness within seconds is acceptable.
- Background jobs that export, aggregate, or sync data.
- Read-heavy API endpoints for data that changes rarely.
Reads that follow a write are the dangerous ones. If a user submits a form and the next page loads from a lagging replica, the new record may be missing, which looks like data loss. Reads used to make decisions inside a transaction, such as checking inventory before an order, should also stay on the primary.
How Do You Get Read-Your-Writes Consistency?
There are several practical patterns, with different complexity. The simplest is to send a user's reads to the primary for a short window after they perform a write, using a timestamp stored in the session. Another approach is to route entire critical flows, such as checkout, to the primary, and use replicas only for browsing.
A more precise method uses log positions. After a write, record the primary's current log sequence number, and before reading from a replica, check that the replica has replayed at least that position, or wait briefly until it has. This guarantees the replica includes the write without sending all traffic to the primary, at the cost of added code and a small wait.
-- On the primary, after the write:
SELECT pg_current_wal_lsn();
-- On the replica, before reading:
SELECT pg_last_wal_replay_lsn() >= '0/3000148'::pg_lsn AS caught_up;
Synchronous replication can remove staleness for chosen replicas, but commits then wait for acknowledgment, which adds latency and can block writes if the replica becomes unavailable. It is a trade-off for specific needs, not a general fix.
How Should You Monitor Lag?
Measure lag in both bytes and time. The primary exposes per-replica write, flush, and replay delays in its replication statistics view, and a replica can report the timestamp of the last replayed transaction. Remember that time-based lag can look large on an idle primary because no new transactions arrive, so combine measures.
Set alerts and define behavior for high lag, such as sending reads back to the primary or failing readiness for that replica. Also plan capacity: replicas help scale reads, but they do not scale writes, and every replica adds replay and network cost.
Frequently Asked Questions
How much replication lag is normal?
Often milliseconds under light load, and seconds or more during heavy writes or conflicts. Define an acceptable lag for each use case and alert when it is exceeded.
Can I write to a read replica?
No. A streaming replica is read-only. Writes must go to the primary, and promoting a replica turns it into a new primary.
Why was my query cancelled on the replica?
Probably a recovery conflict, where replay needed to remove rows your query still required. Shorten the query, adjust standby delay settings, or use a dedicated replica for long reports.
Do replicas improve write performance?
No. They offload reads only. Writes still happen on the primary, and each replica adds some overhead to it.
Summary
Replicas scale reads but introduce staleness, so route only delay-tolerant queries to them and protect read-after-write flows. Use session windows or log position checks for consistency, and monitor lag in both bytes and time. Verify replication settings and recovery conflict behavior in the PostgreSQL documentation for your version.