rsc-contract
v0.1.1
Published
Contracts, diagnostics and budgets for React Server Components boundaries.
Maintainers
Readme
rsc-contract
Contracts, diagnostics and budgets for React Server Components boundaries.
rsc-contract is a static analysis tool that helps you understand and control
what crosses the Server → Client boundary in React Server Components (RSC):
which modules are client-side, which values cross the boundary, how big the
estimated payload is, and whether that payload regressed since your baseline.
npm install -D rsc-contract
npx rsc-contract checkHonesty note. This is static, best-effort analysis. It cannot prove every runtime property of JavaScript. Findings are classified as
safe/unsafe/unknown, andunknownis never reported as an error. Payload numbers are static estimates, clearly labeled as such — they are not runtime Flight measurements.
What is an RSC boundary?
In React Server Components, the module graph is split in two:
- Server modules run only on the server (they may use databases, secrets, Node.js APIs).
- Client modules (files with the
'use client'directive, plus everything they import) run in the browser.
When a server component renders a client component, the props cross a
serialization boundary: the React Flight protocol must serialize them.
Functions, class instances, WeakMaps, database clients and Node.js streams
cannot cross — and huge props silently grow your RSC payload.
rsc-contract makes those boundaries and their costs visible, checked and
enforced in CI.
CLI
rsc-contract check # run rules, report diagnostics (exit 1 on errors)
rsc-contract analyze # diagnostics + payload estimate + budgets
rsc-contract analyze --output .rsc-contract/report.json
rsc-contract diff .rsc-contract/report.json
rsc-contract graph # print the Server/Client module graph
rsc-contract --help | --versionFormats: --format pretty (default), --format json (versioned, machine
readable), --format ci (single-line file:line:col CODE severity message,
IDE/GitHub friendly).
Exit codes: 0 — clean; 1 — errors or budget exceeded; 2 — usage error.
Example output
RSC001
Value cannot safely cross the Server to Client boundary.
Component: ProfileCard
Prop: onSave
Why:
Functions cannot cross the Server -> Client boundary.
Suggestion: Pass a serializable DTO instead (plain objects, strings, numbers, booleans).Configuration
// rsc-contract.config.mjs
import { defineConfig } from 'rsc-contract';
export default defineConfig({
include: ['src/**/*.{ts,tsx}'],
exclude: ['node_modules', '.next'],
budgets: {
rscPayload: '200kb', // max estimated RSC payload
clientBoundary: '50kb', // max estimated payload per boundary
clientDependency: '150kb', // max estimated package footprint in client graph
},
rules: {
serialization: 'error',
serverOnlyImport: 'error',
largeBoundary: 'warning',
},
tsconfig: './tsconfig.json', // path aliases (also auto-discovered)
});.json and .mjs/.cjs/.js configs are supported; .ts configs work on
Node versions with native TypeScript support.
Rules
| Code | Rule | Default | Detects |
|------|------|---------|---------|
| RSC001 | serialization | error | Values crossing the boundary that Flight cannot serialize (functions, class instances, WeakMap/WeakSet, symbols, server objects) |
| RSC002 | serverOnlyImport | error | Node built-ins and known server packages (db drivers, etc.) imported from the client graph |
| RSC003 | boundaryAnalysis | info | Server→Client boundary map; client modules importing server modules (error) |
| RSC004 | largeBoundary | warning | Boundary prop payload above budgets.clientBoundary (estimated) |
| RSC005 | clientDependency | warning | Heavy third-party packages in the client graph (estimated footprint) |
| RSC006 | secretLeak | warning | Secret-bearing props (apiKey, token, …) crossing the boundary. Values are always redacted |
Codes are stable and never reused for a different problem.
Budgets
RSC budget exceeded
Budget: 200 KB
Actual: 384 KB
Difference: +184 KB (+92%)Exceeding a budget in check/analyze/diff produces a non-zero exit code —
safe to enforce in CI.
Diff (baseline comparisons)
npx rsc-contract analyze --output .rsc-contract/report.json
git add .rsc-contract/report.json
# later, or in CI after a PR changes code:
npx rsc-contract diff .rsc-contract/report.jsonThe diff compares payload estimates, client dependencies, boundaries and diagnostics between the baseline snapshot and the current analysis.
CI (GitHub Actions)
- run: npm ci
- run: npx rsc-contract check
- run: npx rsc-contract analyze --output .rsc-contract/report.json
- run: npx rsc-contract diff .rsc-contract/base.jsonSee examples/ci and .github/workflows.
Limits (please read)
- Static, best-effort. Values whose origin cannot be determined statically
are reported as
unknownwithinfoseverity, never as errors. - Payload numbers are estimates derived from the source text of boundary
props and the client module graph. They are useful for trends and budgets,
not byte-accurate Flight measurement. Implement the
RscPayloadProviderinterface to plug in real runtime measurements. - Package footprints are approximations of on-disk size; tree-shaking and bundling are not modeled.
'use client'is detected by directive (with comments/whitespace allowed before it), including through barrel re-exports, aliased paths and dynamic imports. Framework-specific conventions (e.g. Next.js route groups) are not modeled yet.
Architecture
See docs/architecture.md for the pipeline, the parser
choice (TypeScript Compiler API), the rule engine and how to add your own
rules via createRule / registerRule.
Framework support
The core is framework-agnostic. The built-in node adapter resolves modules
with tsconfig paths and standard node_modules resolution — it works for
Next.js App Router, React Router RSC mode, and custom setups that follow the
'use client' convention. Dedicated adapters (deeper route/payload
integration) are planned; none are included yet.
Contributing
npm install
npm test
npm run typecheck
npm run buildFixtures live in fixtures/ and run as part of the test suite. New rules need
a fixture that exercises real behavior, not just the happy path.
License
MIT
