Request-scoped DI containers in App Router / RSC
Hi! I’m experimenting with a small TypeScript dependency injection library and recently added a Next.js App Router / React Server Components adapter.
Links:
- GitHub: https://github.com/bezmen-e/di-craft
- Next.js adapter docs: https://github.com/bezmen-e/di-craft/blob/main/docs/next.md
- App Router demo: https://github.com/bezmen-e/di-craft-next-demo
The main idea is to keep the core DI container framework-agnostic and expose the Next-specific behavior through separate subpath exports:
import { createNextDi } from "di-craft/next/server";import { hydrate } from "di-craft/next/client";The model is:
- create one root container on the server;
- create a child container per request/render;
- use
React.cacheas the request memoization primitive for RSC; - keep React/Next out of the core package;
- avoid moving the DI container to the client;
- pass only serializable state snapshots from server state entities to client state entities.
So instead of this:
server DI container -> client DI containerit uses this:
server state -> serializable snapshot -> client stateThe adapter also has an explicit helper for Route Handlers and Server Actions, where the request container can be disposed after the callback.
The demo covers:
- Page / RSC request scope;
- nested Server Components;
- Route Handler;
- Server Action;
- parallel requests;
- client hydration from a server snapshot.
Demo source:
Note: the demo is intended for a real local Node.js environment or Vercel deployment. StackBlitz/WebContainer environments may fail with current Next.js dev runtime limitations around Turbopack/Webpack fallback and RSC internals.
I’m mostly trying to validate the userland pattern, especially these parts:
- Is
React.cachethe right primitive for request-scoped userland containers in RSC? - Is there any recommended lifecycle/disposal pattern for request-scoped resources after an RSC render?
- Does the
server state -> serializable snapshot -> client statemodel fit App Router boundaries well? - For progressive state delivery, should this just lean on Suspense/streaming, or is there a reasonable pattern for partial snapshots?
This is not a request for framework integration. I’d be happy to hear any feedback, corrections, or advice around request lifecycle, disposal, and state snapshots in App Router/RSC.