Skip to content

liamross/nextjs-cache-inspector

Repository files navigation

Next.js Cache Inspector

What does it do?

Provides advanced dev tools for debugging cache

  • See all cache keys and their read/write ratios
  • See which cache keys are used on a page
  • Operations are grouped by request and the instance where they originate (component, function etc.)

Warning

I am no longer working on this but it was a fun experiment and deep dive into the inner workings of Next.js caching. This may also be out-of-date, it works as of Next.js 15.3.1-canary.8.

The original goal of this repository was to create a cache-as-a-service dev-tools product that was a drop-in replacement for Vercel's cache. This made sense at the time cause Vercel's cache was super barebones, and I thought I could make a better one with deep insights and better developer experience.

They now offer better insights (still not amazing but better). However I still think there's a place for an open-source dev-tool to help with cache debugging. If I have more time later I'll revisit this, since there is essentially a fully-working dev-tool in this code if you separate out all the attempt-at-a-real-product wrapper.

Original full-product vision:

  • Invalidate from anywhere, not just inside nextjs
  • Optimizations are automatically flagged
  • Realtime refetches on client side on cache update
    • Uses pages soft cache keys to smart reload only those pages
  • Automatic instrumentation

If you are interested in poking around

Basic architecture:

  1. There is code in /apps/cache/src/ that creates a client component to wrap the next.config.ts. This proxies requests to Next.js' local dev cache, but also sends telemetry to a localhost server.
  2. That localhost server runs on --port 3210 in this code (/apps/web) and receives those telemetry pings at an endpoint and displays them / groups them in a UI.
  3. The code in /packages/shared/src/ contains all the hacks and fun stuff, like accessing the AsyncLocalStorage instances that Next.js uses to pass information to children in order to climb up the cache tree and determine the source functions.

Screenshots from the app

Requests

Grouped by request, with operations grouped by function or component instance.

Note: for testing all actions have a 1 second delay, hence the 1000+ ms runtime for any functions.

Requests

Cache operations

Streamed-in operations in a log-style format.

Cache operations

Interesting

  • New cache handler removes soft tags which makes it easier to reason about cache keys but harder to determine which page a cache is associated with
  • in experimental.cacheHandlers you can pass in a custom named cache handler (ex: custom_name) and access it using "use cache: custom_name" which is good for debugging and incremental adoption!

Cache patterns

How Next.js deals with soft tags (revalidating paths).

If you invalidate a path then visit it, you will see a successful get but then a set after. This is because the stale tags are managed by nextjs and not the cache handler.

Next.js will call get to get all values on the path, then call getExpiration for the path. The cache is responsible for storing the last called expireTags for any given tag, and therefore will return a value that is younger than the timestamp of the CacheEntry.

[0] use-cache: proxy:expireTags [ '_N_T_/' ]
[0] use-cache: proxy:get ["development","c04becf4cc8dadd3ede715797356d1ebe1afa20ec7",[{"tag":"query-a"}],"269"]
[0] use-cache: proxy:getExpiration [ '_N_T_/layout', '_N_T_/page', '_N_T_/' ]
[0] use-cache: entry was created at 1744761477734.9055 before implicit tags were revalidated at 1744761483981
[0] use-cache: discarding stale entry ["development","c04becf4cc8dadd3ede715797356d1ebe1afa20ec7",[{"tag":"query-a"}],"269"]

Example revalidate path

Fetching data in same request as revalidation

If you fetch data with the same tag as the revalidation, it will be fetched before the revalidation is complete, since it happens in the same function and the lifecycle executes any revalidations after the function completes. You will end up with a MISS, then a SET, then a DEL in that order over and over again.

Example revalidate fetch

About

Advanced dev tools for debugging Next.js cache

Resources

Stars

Watchers

Forks

Contributors