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:
- npm: https://www.npmjs.com/package/di-craft
- GitHub: GitHub - bezmen-e/di-craft: A tiny, type-safe dependency injection container for TypeScript · GitHub
- Next.js adapter docs: di-craft/docs/next.md at main · bezmen-e/di-craft · GitHub
- App Router demo: GitHub - bezmen-e/di-craft-next-demo · GitHub
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 container
it uses this:
server state -> serializable snapshot -> client state
The 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.