
Readyset has always been defined by our incremental dataflow engine. It compiles your SQL into a dataflow graph where base table nodes ingest the replication stream (binlog/WAL) from tables being replicated to Readyset. Internal nodes apply joins, filters, and aggregates, while reader nodes hold the materialized result. Because writes flow through the graph and only affected nodes are updated via incremental view maintenance, the cache stays updated in real-time. Reads are simple lookups on the
Vinicius Grippa
2026-03-05 · 7 min read
Readyset has always been defined by our incremental dataflow engine. It compiles your SQL into a dataflow graph where base table nodes ingest the replication stream (binlog/WAL) from tables being replicated to Readyset. Internal nodes apply joins, filters, and aggregates, while reader nodes hold the materialized result.
Because writes flow through the graph and only affected nodes are updated via incremental view maintenance, the cache stays updated in real-time. Reads are simple lookups on these reader nodes, providing sub-millisecond latency for fresh data, a process we call deep caching.
Shallow Caches are the high-performance partner to our core Deep Cache engine, designed to reduce the ramp-up time while providing near 100% query coverage. While Deep Caches are built for mission-critical traffic that demands real-time data updates, Shallow Caches handle the rest by prioritizing speed and upstream database protection.
This "catch-all" approach works for any SELECT query, regardless of complexity—making it the ideal solution even for heavy analytical joins or dashboards where a smaller freshness window is a small price to pay for a 1000x speed boost.
The most common approach today remains using in-memory key-value data stores such as Redis to also serve as a SQL query cache. However, unlike Redis, which forces developers to manually write cache invalidation logic and handle "miss" scenarios in the application code, Readyset caching continues to manage the entire lifecycle. Developers do not need to perform any manual tasks to ensure cache coherence; the system handles this automatically, providing a seamless, plug-and-play experience that requires no application code changes.
While this is a TTL-based layer, adjusting TTL values for a cache is optional. Readyset already handles refreshing your results after a TTL expires, and future updates will enable the caching system to subscribe to your replication stream to trigger shallow cache refreshes automatically based on replication streams and dynamically adjust TTLs based on how data changes in your backend database.
A common issue with applications using general purpose key-value data stores like Redis as a SQL query cache is the latency spike that occurs when a TTL expires, as all clients must suddenly wait for the application to pull new data from the backend. Shallow caching in Readyset prevents this by refreshing caches atomically and in the background. Clients never experience the swap to new results, which is how a true read-through cache should behave.
The end result is a consistent, sub-millisecond access experience for cached data. By merging cache invalidation and refresh into a single component, Readyset removes the burden from the application and ensures a smooth performance profile that a Redis-style caching approach cannot match.

Let’s take a look at some examples to see how this works in practice. Using the MySQL Employees Database (~300k employees, ~2.8M salaries), we ran a heavy aggregation (joins, GROUP BY, HAVING). Such queries can be cached with either Deep or Shallow Caches.
Note: This specific query was selected simply as an example of a heavy analytical workload.
Before caching, this query took 6.62 seconds to execute on the standard database. Once cached in Readyset, the execution time dropped to just 0.01 seconds.
-- Original Query Execution: 6.62 seconds
-- Readyset Cached Execution: 0.01 seconds
SELECT DISTINCT e.emp_no, e.first_name, e.last_name, MAX(s.salary) AS highest_salary
FROM employees e
JOIN salaries s ON e.emp_no = s.emp_no
GROUP BY e.emp_no, e.first_name, e.last_name
HAVING highest_salary > 120000
ORDER BY highest_salary DESC
LIMIT 10;
Such queries can be supported by either deep or shallow caching. Shallow caching refreshes these results after backend changes in roughly 5–8 seconds, though this interval is configurable. Deep caching avoids upstream queries entirely by using the replication stream to update the cache within milliseconds of receiving records from the backend database.
Shallow Caches aren't a "dumb" cache. They include built-in safeguards to keep your upstream database healthy:
Note: REFRESH
Shallow caches are always available in Readyset—there’s no separate “shallow-only” binary or install. You run Readyset as usual; shallow caching is built in.To influence how caches are created when you don’t specify DEEP or SHALLOW, set --cache-mode (or env CACHE_MODE) at startup:
Use the standard config file (e.g. /etc/readyset/readyset.conf). It’s env-style: one KEY=value per line. Add or uncomment these for shallow cache:
## Shallow cache behavior
## deep | shallow | deep-then-shallow
CACHE_MODE=deep-then-shallow
We can also use per-cache settings to override the default TTL, REFRESH, and COALESCE policy in the DDL for specific scenarios. Consider this example:
CREATE SHALLOW CACHE
POLICY TTL 30 SECONDS REFRESH 2 SECONDS
COALESCE 5 SECONDS
FROM
SELECT DISTINCT e.emp_no, e.first_name, e.last_name, MAX(s.salary) AS highest_salary
FROM employees e
JOIN salaries s ON e.emp_no = s.emp_no
GROUP BY e.emp_no, e.first_name, e.last_name
HAVING highest_salary > 120000
ORDER BY highest_salary DESC
LIMIT 10;
Think of it like this:
TTL 30 SECONDS
Very similar to a Redis-style TTL: after 30 seconds of no one reading this entry, Readyset treats it as expired and will eventually evict the entry.
REFRESH 2 SECONDS
This is the part that Redis-style approach doesn’t give you out of the box. As soon as a cached result is 2 seconds old, the next read both:
COALESCE 5 SECONDS
This is built‑in thundering‑herd protection. If a bunch of clients all miss the cache (or hit it right after eviction) within 5 seconds of each other, Readyset only sends one query to the database and lets the others wait briefly for that result, instead of slamming the DB with 50 identical queries like a naive Redis-style pattern.
With the introduction of Shallow caches alongside our now default Deep caching approach to the Readyset solution, we are excited to bring options for our customers to offload even more queries to Readyset for up to 70% in cost savings over read replicas with zero code changes.
You can learn more about shallow cache and how to get started here. As always, if you have questions for us, reach out to us on slack or send a note to - hello@readyset.io.
Modern applications demand instant performance, even under unpredictable load. Readyset helps you eliminate slow queries, stabilize latency, and scale confidently.
Revolutionize your database performance with Readyset
Serve requests at sub-millisecond latencies with the modern database scaling and query caching system for MySQL and PostgreSQL.
Join our newsletter
Stay updated with the latest news, insights, and developments from Readyset — straight to your inbox.