A packed canvas backpack in a vehicle, representing a cache: a store of items kept close and ready, but opaque until you look inside

Next.js Hides Its Cache, Redis Doesn’t: The Observability Gap

The current stack caches everything through Redis directly. Ask it what’s happening right now, hit rate, what’s getting evicted, how full it is, and it answers immediately: redis-cli INFO stats returns real numbers in under a second. Next.js’s caching model never answered that question the same way. Not because the caching itself was worse, but because the cache lived inside the framework as an implementation detail, and implementation details don’t usually come with a dashboard.

That’s the actual argument here. It’s not about which cache is faster. It’s about which cache you can see.

TL;DR

  • Redis exposes real, native cache metrics through its own INFO stats command: keyspace_hitskeyspace_missesevicted_keys, current memory usage, all queryable in real time with no extra tooling.
  • Next.js’s caching layer has no equivalent built into the framework for self-hosted deployments. An open Next.js discussion confirms there’s still no programmatic way to know whether a given response was served from cache or not, only development-mode logging, which was reduced in later versions.
  • Next.js 16’s newer caching model (use cachecacheLifecacheTag) doesn’t close the gap either. It changed how caching is expressed, not whether a self-hosted developer can inspect what it’s doing.
  • Vercel’s own hosted infrastructure does provide this visibility, an Observability dashboard with cache hit metrics, but that’s a platform feature for deployed Vercel projects, not something self-hosted Next.js gets by default.
  • A concrete example: switching caching to something directly inspectable surfaced a real, fixable number, a cache hit rate that had been sitting invisible the entire time it was managed as an internal framework detail.

What Redis actually exposes

Redis’s INFO stats section returns keyspace_hits and keyspace_misses as running counters, straightforward enough to compute a live hit rate from: keyspace_hits / (keyspace_hits + keyspace_misses). The same section reports evicted_keys, so a sudden spike in evictions, a sign the cache is undersized or the eviction policy is wrong, shows up immediately instead of showing up later as a performance regression nobody can explain. MONITOR goes further and streams every command Redis processes in real time. None of this requires third-party tooling to access. It’s the default behavior of the cache itself, documented directly in Redis’s own reference docs.

This isn’t a case of Redis having better dashboards bolted on. It’s a case of the cache being a thing you own and can interrogate directly, rather than a thing living inside someone else’s abstraction.

What Next.js’s caching layer doesn’t expose

long-running discussion on the Next.js repository, opened in 2023 and still unresolved as of its most recent reply, asks for exactly the capability Redis provides by default: a way to know, in code, whether a given response was served from cache. No Next.js maintainer has weighed in with an official answer, but the developers who tested it directly converge on the same finding: that capability doesn’t exist. What does exist is development-mode console logging that prints HIT or MISS, and one commenter notes even that was removed after version 13.4.12 before later reappearing as a dev-only setting. Another commenter, working through a real invalidation use case in detail, states plainly that this visibility “already works by default with Vercel,” the clear implication being that it doesn’t work by default anywhere else.

That discussion concerns the caching model that predates Next.js 16’s use cachecacheLife, and cacheTag directives. Nothing in Next.js 16’s own documentation describes a new mechanism for exposing cache state to application code either, and the newer directives sit on top of the same underlying caching layer the discussion above is about. The redesign changed how caching is expressed, not whether a self-hosted developer can inspect it.

Vercel’s own dashboard is the tell

Vercel’s Observability suite includes a dedicated view for cache hit metrics on deployed projects. That’s a real answer to the observability problem, it’s just not a framework-level answer. It’s a hosting-platform feature available to projects deployed on Vercel’s own infrastructure. This connects directly to something already true of Next.js’s Data Cache more broadly: on Vercel, the cache lives in managed, external infrastructure the platform operates and instruments. Self-hosted, that infrastructure and its instrumentation don’t come along for free, the developer has to build both.

That’s a fair design choice for Vercel to make. It’s also the exact shape of the pattern this piece is about: framework-managed caching can be made observable, the tooling to do it clearly exists, it’s just not something a self-hosted developer gets without either building it themselves or moving to the platform that already has it.

What this actually cost, concretely

One real number came out of switching caching to something directly inspectable: a cache hit rate that had been running invisible the whole time it was a framework-managed detail became visible and addressable the moment it lived somewhere with real metrics attached. That’s not a benchmark claim, it’s a single data point, but it’s the right kind of data point: a number that existed the entire time and simply couldn’t be seen until the cache stopped being someone else’s implementation detail.

Frequently asked questions

Does this mean Redis is better than Next.js’s cache?

Not as a general claim, no. This isn’t about raw performance, it’s about visibility. A framework-managed cache can be just as effective while still being harder to inspect, tune, or debug, because effectiveness and observability are different properties. The argument here is specifically about the second one.

Could Next.js add this kind of visibility in the future?

Nothing rules it out. The gap exists in the current self-hosted experience, not as a permanent architectural limit. Given that Vercel’s own hosted platform already solves this for deployed projects, the underlying capability clearly exists; it just hasn’t shipped as a first-class, framework-level feature for self-hosted use.

Is this specific to Next.js, or true of framework-managed caches generally?

The pattern is general. Any cache implemented as an internal detail of a framework or platform, rather than exposed as something the developer directly owns and can query, carries the same risk: it works until something goes wrong, and there’s no built-in way to see what.

Related reading

This is a direct follow-up to the Vercel Data Cache section of the memory leak case study, which covers the same self-hosted-versus-managed-infrastructure gap from the memory side rather than the observability side.

RSS Feed Newsletter
Contact us

Latest Blog Posts