YugabyteDB Follower Reads: Local Reads Without Pretending Data Is Fresh
Follower reads let a YugabyteDB session read from a local Raft follower instead of a cross-region leader. Here's the trade, a worked YSQL example, and how to verify it.
06 Jun 2026, 10:16 UTC

If your YugabyteDB cluster spans regions and your reads keep landing on a tablet leader in another continent, the fix is not always a bigger cache or a read replica. YugabyteDB ships a bounded-staleness read path — follower reads — that lets a session read from a local Raft follower instead of the leader. The trade is explicit: you accept data that may lag the latest committed write by a window you configure.
The default read path crosses regions
YugabyteDB splits each table into tablets. Each tablet is a Raft group with one leader and one or more followers, and the leader is the only replica that serves strongly consistent reads and writes. In a multi-region deployment, the leader for a given tablet lives in exactly one region. A client in another region that issues an ordinary SELECT pays a round trip to that leader, even though a full copy of the data is sitting on a follower a few milliseconds away.
That round trip is the cost you are trying to remove. It is not a correctness problem — it is a latency problem, and it only shows up when the leader and the reader are geographically separated.
What follower reads change, and what they don't
Follower reads change which replica answers the query. Instead of routing to the leader, the session is allowed to read from a follower whose applied Raft log is within a configured staleness bound. Two settings control this in YSQL:
yb_read_from_followers— enables the follower-read path for the session (or for a role or database, if set persistently).yb_follower_read_staleness_ms— the maximum lag, in milliseconds, a follower may have relative to the leader and still serve the read.
What they do not change: follower reads are not linearizable. They are a bounded-staleness mechanism by design. A follower read can return a value older than the most recent committed write, as long as it is within the staleness window. If your application needs read-your-writes — write a row, then immediately read it back and expect to see it — that read must stay on the leader.
Follower reads are also not the same thing as read replicas or geo-partitioning. Read replicas are non-voting copies that do not participate in Raft elections; followers are full Raft members that can become leader. Geo-partitioning changes where rows live; follower reads change which replica answers. Conflating the three leads to configuration that does not do what you expect.
A worked example
Assume a three-region cluster with a table whose tablet leader is in us-east and a follower in eu-west. A dashboard service running in eu-west queries a product catalog. Any latency figures you see here are illustrative — actual cross-region round-trip time depends on geography and network path — but the shape of the comparison is the point.
Run this in ysqlsh, connected to the cluster as a user permitted to set session GUCs. Session-level SET is the least invasive option; making it persistent requires ALTER DATABASE or ALTER ROLE, which typically needs elevated privileges.
-- Baseline: default path, reads go to the tablet leader
EXPLAIN ANALYZE
SELECT product_id, name, price
FROM catalog
WHERE product_id = 42;
-- Follower-read path for this session only
SET yb_read_from_followers = on;
SET yb_follower_read_staleness_ms = 10000;
EXPLAIN ANALYZE
SELECT product_id, name, price
FROM catalog
WHERE product_id = 42;
Compare the reported execution time between the two runs from a client in the non-leader region. Whether EXPLAIN output explicitly labels the follower-read path varies by release — check the documentation for your installed version rather than assuming the plan text will say so.
To confirm the placement assumption, list the tablet peers for the table and note which node holds the leader. The YB-Master web UI shows this per tablet, and yb-admin can list tablet information from the command line. If the leader for your hot table is already in the same region as the reader, follower reads buy you little.
To see the staleness trade directly, write a row and read it back through the follower-read session. If the new value is not visible immediately, that is expected behavior within the staleness window, not a bug.
Where this is the wrong tool
Follower reads fit read-heavy, staleness-tolerant workloads: dashboards, catalog browsing, reporting queries — anything where a ten-second-old answer is still a correct answer. They fit poorly for:
- Reads that must reflect the caller's own recent write.
- Single-region clusters, where leader and followers are roughly equidistant and the benefit largely disappears.
- Workloads that need strict linearizability for correctness, not just freshness.
The practical pattern is to enable follower reads per session or per role for the services that can tolerate it, and leave everything else on the default path. That keeps the freshness decision close to the code that actually knows the requirement.
Checking the result and cleaning up
Verification, in order:
- Confirm the GUC names, defaults, and the minimum version that supports follower reads in the release notes for your installed YugabyteDB version. These have changed across releases.
- Confirm tablet leader placement for the table under test.
- Measure the same query with follower reads off and on, from a client in the non-leader region.
- Run the write-then-read test to observe the staleness window in practice.
If you set the GUCs at session level, the change disappears when the connection closes; use RESET yb_read_from_followers; and RESET yb_follower_read_staleness_ms; to return to defaults mid-session. If you set them at database or role level, revert with the corresponding ALTER DATABASE ... RESET or ALTER ROLE ... RESET.
The decision is not "are follower reads faster" — in a multi-region cluster they usually are — but "can this specific query tolerate an answer that is a few seconds behind." Answer that per query, not per cluster.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.