Problem
deferRegistry (packages/static/src/rsc/defer.tsx) is a module-level singleton in the RSC environment. In dev, every HTML render calls defer() with fresh crypto.randomUUID() IDs and registers new entries, but entries are never evicted:
- pending entries retain the React element,
- loaded entries retain the entire rendered payload string via
drainPromise.
Over a long dev session (many page loads / HMR-triggered re-renders), memory grows without bound. The registry only resets when the RSC module itself is reloaded by HMR. Production builds are unaffected (the process exits after the build).
Suggested fix
Scope or expire dev registrations, e.g.:
- attach a timestamp and evict entries older than some TTL after they reach
ready/error, or
- track registrations per HTML render and drop the previous generation's entries when a new top-level render for the same entry begins (keeping a short grace period so in-flight client fetches still resolve).
Found during a framework audit.
Problem
deferRegistry(packages/static/src/rsc/defer.tsx) is a module-level singleton in the RSC environment. In dev, every HTML render callsdefer()with freshcrypto.randomUUID()IDs and registers new entries, but entries are never evicted:drainPromise.Over a long dev session (many page loads / HMR-triggered re-renders), memory grows without bound. The registry only resets when the RSC module itself is reloaded by HMR. Production builds are unaffected (the process exits after the build).
Suggested fix
Scope or expire dev registrations, e.g.:
ready/error, orFound during a framework audit.