Skip to main content
Metrics type: Key MetricsCategory: Replication

At a glance

The number of seconds a Supabase read replica trails behind the primary database. Read replicas are a paid, region-pinned feature: they exist to serve read-routed traffic closer to users and to offload reporting queries from the primary. Replication is asynchronous, so a replica is always a little behind. Small lag (under a second) is normal and harmless. Sustained lag means read-routed queries return stale rows: a user updates their profile, reads it back from a lagging replica, and sees the old value. For an ops team, this card answers “can I trust what my read replicas are returning right now?”

Calculation

Supabase read replicas use Postgres streaming replication, which is asynchronous: the primary commits a transaction, writes it to the Write-Ahead Log (WAL), and ships WAL records to each replica, which then replays them. Lag is the time between a commit landing on the primary and being replayed on the replica. The value is computed per replica as:
evaluated on the replica. pg_last_xact_replay_timestamp() returns the commit timestamp of the most recent transaction the replica has applied. Subtracting it from the current time gives how far behind “now” the replica is in wall-clock terms. The card polls each replica in real time and reports the maximum across all of them, because a single lagging replica is enough to serve stale reads. A subtlety: on a perfectly idle primary (no writes at all) the replica has nothing to replay, so pg_last_xact_replay_timestamp() stops advancing and naive lag appears to climb even though the replica is fully current. The engine corrects for this by cross-checking the WAL LSN positions: if the replica’s replay LSN equals the primary’s current LSN, lag is reported as zero regardless of the timestamp gap. This avoids false alerts during quiet periods (overnight, low-traffic windows). The 10-second alert threshold is deliberately generous. Streaming replication within a single region typically holds sub-second lag; cross-region replicas (the primary in one region, the replica in another) carry network round-trip overhead and may sit at one to three seconds under load. Ten seconds is the point at which read-your-own-writes breakage becomes user-visible and worth paging on.

Worked example

A SaaS platform team runs a Supabase project on the Team tier with the primary in London (eu-west-2) and two read replicas: one in London for offloading reporting queries, and one in Virginia (us-east-1) to serve North American users with lower read latency. Snapshot taken on 14 Apr 26 at 09:40 BST during a batch import. The Nerve Centre headline displays 14.2s (the worst replica) outlined amber, with the alert tripped because it exceeds the 10s threshold. Reading the situation:
  1. The London replica is healthy (0.4s). Same region as the primary, sub-second lag, no concern. Reporting queries routed here are effectively current.
  2. The Virginia replica is lagging (14.2s). A batch import started at 09:35 is pushing a heavy write stream through the primary. The cross-region replica cannot replay WAL fast enough over the transatlantic link, so it has fallen 14 seconds behind. North American users reading from this replica during the import window will see data up to 14 seconds stale: a user who just saved a setting and refreshes may see the old value.
What the team should do:
  1. Confirm it is the import, not a broken replica. Lag that rises with a known write burst and recovers afterwards is expected behaviour, not a fault. Pair with Database Queries per Second (live): if QPS spiked at 09:35, the lag is import-driven.
  2. Route read-your-own-writes traffic to the primary during imports. Any flow where a user reads back something they just wrote should target the primary (or the same-region replica) so the staleness window never shows. Pure reporting and analytics reads can tolerate the lag.
  3. Watch for recovery. Once the import finishes, lag should drain back to baseline within a minute or two as the replica catches up. If it stays high after writes stop, that is a replica problem (network saturation, undersized replica instance), not a load problem, and warrants raising with Supabase support.
The key lesson: cross-region replicas trade freshness for read latency. A 14-second blip during a planned batch import is acceptable; the same lag at 14:00 on a normal trading afternoon is not, and would mean the replica or its network link is degraded.

Sibling cards to reference together

Reconciling against the source

Where to look in Supabase and Postgres:
Supabase project Reports / Database section for the per-replica replication lag chart, broken down by region. SELECT now() - pg_last_xact_replay_timestamp() AS lag; run on the replica connection for the live timestamp-based lag. SELECT * FROM pg_stat_replication; run on the primary for sent_lsn, replay_lsn, and the per-replica replay_lag interval (the authoritative server-side view). SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS bytes_behind FROM pg_stat_replication; for lag measured in WAL bytes rather than seconds.
Why our number may legitimately differ from Supabase’s own chart: The most authoritative single check is pg_stat_replication on the primary, which Postgres maintains directly. If that view’s replay_lag agrees with this card, the reading is sound.

Known limitations / FAQs

My project has no read replicas. What does this card show? “Not provisioned” or a dash. Read replicas are a paid feature available on the Pro tier and above, provisioned per region. If you have not added any, there is nothing to lag and the card is informational only. Once you add a replica, the card begins reporting immediately. Lag spikes every night around 02:00 then clears. Is something broken? Almost certainly a scheduled batch job (an import, a nightly aggregation, a VACUUM, or a large UPDATE) pushing a burst of WAL through the primary. The replica falls behind during the burst and catches up after. This is normal asynchronous-replication behaviour. Only worry if the lag does not recover once the write burst ends. The number climbs even though there are no writes happening. This is the idle-primary artefact. pg_last_xact_replay_timestamp() stops advancing when there is nothing to replay, so naive timestamp lag appears to grow. Vortex IQ corrects for this by checking WAL LSN positions and reports zero when the replica’s replay LSN matches the primary. If you query the replica directly with the raw timestamp method, you will see the inflated number; trust pg_stat_replication on the primary instead. What is the difference between lag in seconds and lag in bytes? Bytes (pg_wal_lsn_diff) measure how much un-replayed WAL the replica is holding; seconds measure how far behind in wall-clock terms. A replica can hold a large byte backlog but still be sub-second behind if it is replaying fast. Seconds is the user-facing metric because it maps directly to “how stale is the data my users see”; this card reports seconds. Does lag cause data loss? No. Asynchronous replication delays visibility, it does not lose committed data. Every transaction committed on the primary is durable on the primary regardless of replica state. The replica eventually catches up and applies every WAL record in order. Lag is a freshness problem, not a durability problem. (Data loss is only a risk in a failover scenario where a lagging replica is promoted, but Supabase manages failover and does not promote a replica that is significantly behind.) Why is my cross-region replica always more lagging than my same-region one? Network round-trip time. WAL must travel from the primary to the replica before it can be replayed. A same-region replica is a few milliseconds away; a transatlantic or trans-Pacific replica is tens of milliseconds away, and under heavy write volume that overhead compounds. Cross-region replicas trade a little freshness for much lower read latency for distant users. Budget for a baseline of one to three seconds on cross-region replicas under normal load. Should I route all my reads to replicas to take load off the primary? Only the reads that tolerate staleness. Reporting, analytics, dashboards, and search results are fine on a replica. Read-your-own-writes flows (a user saves something then reads it back, a checkout that re-reads the cart it just wrote) must go to the primary, or you will surface stale rows during any lag window. The usual pattern is “writes and read-after-write to primary; everything else to replicas”.

Tracked live in Vortex IQ Nerve Centre

Read Replica Lag (seconds) is one of hundreds of KPI pulses Vortex IQ tracks across Supabase and 70+ other ecommerce connectors. Nerve Centre runs the detection layer; Vortex Mind investigates the cause when something moves; Ask Viq lets you interrogate any number in plain English. Start for free or book a demo to see this metric running on your own data.