Skip to content

Dev cache parity: make cacheMaxMemorySize: 0 and custom cache handlers fast in dev (TieredCacheHandler) #2110

Description

@github-actions

Summary

Next.js changed dev-mode cache behavior so that cacheMaxMemorySize: 0 and custom cache handlers no longer cause warm reloads to be treated as cold cache misses under Cache Components. The fix introduces a built-in in-memory front handler that fronts the configured (slow/remote) backing handler in dev only, so warm reads resolve in a microtask.

Before the fix, when Cache Components is enabled, next dev treated a 'use cache' value as a miss whenever the read didn't resolve right away. Two dev configurations triggered this even for cached entries:

  1. cacheMaxMemorySize: 0 replaced the built-in default handler with a no-op stub
  2. Custom cache handlers with a slow or remote get didn't return in time

Behavior

  • Size-0 case: Dev now uses a real in-memory handler instead of the no-op stub. The 'use cache' wrapper forces a dynamic cache life for it (revalidate: 0, 5-minute expire) — same treatment private caches receive — so every read serves the stale entry and re-warms in the background. Also fixes the dev private handler, which was sized from cacheMaxMemorySize and degraded to the no-op stub when set to 0.
  • Custom handler case: A new TieredCacheHandler puts a fast built-in in-memory front in front of the user-configured backing. Warm reads serve from the front, writes go through to both tiers, and the front reconciles against the backing in the background (evicting front entries when the backing no longer has them, via an already-expired overwrite since the handler interface has no per-key delete).
  • Dev-only handlers are gated on process.env.__NEXT_DEV_SERVER; production is unchanged (cacheMaxMemorySize: 0 still caches nothing, configured handlers used directly).
  • Dev-only handlers are kept out of the main registered handler set but merged in where tag operations iterate, so revalidateTag still reaches them.

vinext implications

vinext's dev cache layer (see isr-cache.ts / cache-handler config) should consider:

  • Whether vinext exhibits the same dev cold-miss behavior under the new 'use cache' semantics when cacheMaxMemorySize: 0 is configured or when a slow custom handler is used
  • Whether to implement an equivalent dev-only front handler / tiered handler so warm reads in vinext dev don't surface as cold-cache misses
  • Tag invalidation must continue to reach the dev front handler if we add one

This is dev-only parity but matters for users who configure cacheMaxMemorySize: 0 (e.g. to emulate deploy envs) or who plug in a remote cache handler.

Upstream

Related: #1936 (dev cache serve-until-expire), #1937 (persist use cache: private in dev)

Metadata

Metadata

Assignees

No one assigned

    Labels

    nextjs-trackingTracking issue for a Next.js canary change relevant to vinext

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions