Architecture

Package Hierarchy

NextRush's modular package structure — understand dependencies, responsibilities, and how packages fit together.

NextRush uses a modular monorepo architecture. Each package has a single responsibility and explicit dependencies.

This page has two diagrams: "The Big Picture" below is a curated, hand-arranged diagram grouped by architectural layer (Foundation, Core, Adapters, …) for readability. The Dependency Graph (Generated from Source) further down is mechanically produced from every package's real package.json — see the callout there for how, and trust it first if the two ever disagree.

The Big Picture

Loading diagram...

Package Categories

Foundation Layer

These packages form the base of the hierarchy. They depend only on each other — never on higher layers.

PackageResponsibilityDependencies
@nextrush/typesTypeScript types and interfacesNone
@nextrush/errorsHTTP error classestypes
@nextrush/runtimeRuntime detection, BodySourcetypes, errors
import type { Context, Middleware, Extension } from '@nextrush/types';
import { NotFoundError, BadRequestError } from '@nextrush/errors';
import { getRuntime, getRuntimeCapabilities } from '@nextrush/runtime';

Core Layer

The essential packages that make up the framework:

PackageResponsibilityDependencies
@nextrush/coreApplication, middleware compositiontypes, errors
@nextrush/routerSegment trie routingtypes
@nextrush/diDependency injection containerreflect-metadata, tsyringe
import { createApp, compose } from '@nextrush/core';
import { createRouter } from '@nextrush/router';
import { Service, Repository, container } from '@nextrush/di';

Adapter Layer

Platform-specific HTTP handling:

PackageRuntimeDependencies
@nextrush/adapter-nodeNode.js 22+core, runtime, errors, types
@nextrush/adapter-bunBun 1.0+core, runtime, errors, types
@nextrush/adapter-denoDeno 2.0+core, runtime, errors, types
@nextrush/adapter-edgeCloudflare, Vercel Edgecore, runtime, errors, types
import { listen } from '@nextrush/adapter-node';
import { serve } from '@nextrush/adapter-bun';
import { createHandler } from '@nextrush/adapter-edge';

Middleware Layer

Reusable middleware packages. All middleware depends only on @nextrush/types.

PackageResponsibility
@nextrush/body-parserParse JSON, form, multipart bodies
@nextrush/corsCross-Origin Resource Sharing
@nextrush/helmetSecurity headers
@nextrush/compressionResponse compression
@nextrush/rate-limitRate limiting
@nextrush/request-idRequest ID generation
@nextrush/timerResponse time tracking
@nextrush/cookiesCookie parsing and setting
@nextrush/validationStandard Schema request validation
import { json, urlencoded } from '@nextrush/body-parser';
import { cors } from '@nextrush/cors';
import { helmet } from '@nextrush/helmet';
import { compression } from '@nextrush/compression';
import { rateLimit } from '@nextrush/rate-limit';
import { validate } from '@nextrush/validation';

Class Runtime, Extensions & Registrars Layer

@nextrush/class is the unified class-based API — it consolidates the former @nextrush/decorators and @nextrush/controllers split (both packages have been removed — see Deprecations), and re-exports @nextrush/di. Beyond that, the remaining extensions layer is mostly middleware, plus one registrar and one Extension:

PackageResponsibilityDependencies
@nextrush/classDecorators, controller registration, modules, guards, interceptors, filters, lifecycle, request scope. Re-exports @nextrush/di.di, errors, router, types, core (also declared as peerDependencies — see note below)
@nextrush/loggerStructured logging@nextrush/log, types
@nextrush/staticStatic file servingtypes
@nextrush/templateTemplate engine supporttypes
@nextrush/websocketWebSocket supporttypes
@nextrush/eventsEvent system (pub/sub) — the one Extension
import { registerControllers, registerModule } from 'nextrush/class';
import { logger } from '@nextrush/logger';
import { serveStatic } from '@nextrush/static';

Decorators/controllers shims removed — import from nextrush/class

@nextrush/decorators and @nextrush/controllers — the pre-consolidation split — have been removed from the workspace. Import everything from nextrush/class directly; see Deprecations for the exact old-import → new-import map and the automated codemod.

Dev Tools

PackageResponsibilityDependencies
@nextrush/devDevelopment server, build tools, CLI@swc-node/register, @swc/core, tsx

Meta Package

Convenience package that re-exports essentials:

DependencyExports
@nextrush/corecreateApp, compose, Application
@nextrush/routercreateRouter, Router, endpoint
@nextrush/adapter-nodelisten, serve, createHandler
@nextrush/errorsHttpError, all error subclasses
@nextrush/typesContentType, HttpStatus
import { createApp, createRouter, listen } from 'nextrush';

nextrush/class is a separate subpath export of the same meta package — it re-exports @nextrush/class's full surface (decorators, DI, modules, guards, interceptors, filters, lifecycle) without pulling those symbols into the root nextrush import.

Dependency Rules

NextRush follows strict dependency rules: lower packages never import from higher packages, and circular dependencies are blocked at CI. If you encounter an import error, check the hierarchy diagram above.

1. types is the root — no internal dependencies

@nextrush/types → (none)

2. Foundation packages depend only on types

@nextrush/errors → types
@nextrush/runtime → types, errors

3. Core packages depend on foundation

@nextrush/core → types, errors
@nextrush/router → types
@nextrush/di → reflect-metadata, tsyringe

4. Adapters depend on core + runtime + foundation

@nextrush/adapter-node → core, runtime, errors, types
@nextrush/adapter-bun → core, runtime, errors, types

5. Middleware depends only on types

@nextrush/cors → types
@nextrush/body-parser → types

6. The class runtime depends on di + foundation + core/router

@nextrush/class → di, errors, router, types, core

core and router are dependencies AND peerDependencies, not peer-only

packages/class/package.json lists @nextrush/core and @nextrush/router in both its dependencies and its peerDependencies — verified directly against the file, not inferred. This is a deliberate double-declaration (common for a package that both needs a peer's types at compile time and re-exercises its runtime behavior), not a peer-only relationship. Treat @nextrush/class as depending on the full stack below it, same as any other package in this hierarchy. Separately, @nextrush/di uses @nextrush/types at compile time (devDependency) only — its production dependencies are reflect-metadata and tsyringe.

Dependency Graph (Generated from Source)

This graph is generated, not hand-drawn

Everything below this line is produced by apps/website/scripts/internals/generate-dependency-graph.mjs, a script that walks every packages/**/package.json, reads its real dependencies field, and emits the edges below. It does not read this .mdx file or any hand-maintained list — re-run it after adding or changing a package's dependencies and the graph updates itself. Run it from the repo root: node apps/website/scripts/internals/generate-dependency-graph.mjs.

The script scanned 36 package.json files under packages/ (35 publishable packages plus the private, never-published @nextrush/adapter-conformance test suite — see Versioning & Compatibility) and found 67 internal @nextrush/* edges (external dependencies like tsyringe and reflect-metadata are listed per-package below the graph, not as graph nodes — the graph's job is the internal hierarchy).

Loading diagram...

Findings from the generated scan (not visible in the curated diagram above)

Running the script surfaced two facts worth stating plainly rather than folding into the curated diagram, since a hand-arranged diagram can hide exactly this kind of detail:

  • @nextrush/logger depends on @nextrush/log (^0.2.1) — a separately published external package, not a workspace member. It is the one genuine external-runtime-dependency case outside the three named exceptions in Design Principles (reflect-metadata, tsyringe, @clack/prompts). Verified directly against packages/middleware/logger/package.json — this is not a typo in the graph script, @nextrush/log really is declared as a runtime dependency there.
  • nextrush (the meta package) no longer depends on @nextrush/decorators or @nextrush/controllers — both were removed from its dependencies when the two shim packages were deleted from the workspace (see Deprecations). It depends only on @nextrush/class for the class-based API surface now.
Full generated edge list (34 packages, exact dependencies field)
  • @nextrush/adapter-bun 1.0.0 → @nextrush/core, @nextrush/errors, @nextrush/runtime, @nextrush/stream, @nextrush/types
  • @nextrush/adapter-conformance 1.0.0 → (none)
  • @nextrush/adapter-deno 1.0.0 → @nextrush/core, @nextrush/errors, @nextrush/runtime, @nextrush/stream, @nextrush/types
  • @nextrush/adapter-edge 1.0.0 → @nextrush/core, @nextrush/errors, @nextrush/runtime, @nextrush/stream, @nextrush/types
  • @nextrush/adapter-node 3.1.0 → @nextrush/core, @nextrush/errors, @nextrush/runtime, @nextrush/stream, @nextrush/types
  • @nextrush/body-parser 3.1.0 → @nextrush/types
  • @nextrush/class 3.1.0 → @nextrush/core, @nextrush/di, @nextrush/errors, @nextrush/router, @nextrush/types [external: reflect-metadata]
  • @nextrush/compression 3.1.0 → @nextrush/types
  • @nextrush/cookies 1.0.0 → @nextrush/types
  • @nextrush/core 3.1.0 → @nextrush/errors, @nextrush/types
  • @nextrush/cors 3.1.0 → @nextrush/types
  • @nextrush/csrf 1.0.0 → @nextrush/types
  • @nextrush/dev 1.0.0 → (none) [external: @swc-node/register, @swc/core, tsx]
  • @nextrush/di 3.1.0 → @nextrush/types [external: reflect-metadata, tsyringe]
  • @nextrush/errors 3.1.0 → @nextrush/types
  • @nextrush/events 1.0.0 → (none)
  • @nextrush/helmet 3.1.0 → @nextrush/types
  • @nextrush/logger 1.0.0 → @nextrush/log, @nextrush/types
  • @nextrush/form-data 1.0.0 → @nextrush/types
  • @nextrush/openapi 1.0.0 → @nextrush/types
  • @nextrush/rate-limit 1.0.0 → @nextrush/types
  • @nextrush/request-id 1.0.0 → @nextrush/types
  • @nextrush/router 3.1.0 → @nextrush/types
  • @nextrush/runtime 3.1.0 → @nextrush/errors, @nextrush/types
  • @nextrush/static 1.0.0 → @nextrush/types
  • @nextrush/stream 3.1.0 → @nextrush/types
  • @nextrush/template 1.0.0 → @nextrush/types
  • @nextrush/testing 1.0.0 → @nextrush/class, @nextrush/core, @nextrush/di, @nextrush/router, @nextrush/types [external: reflect-metadata]
  • @nextrush/timer 1.0.0 → @nextrush/types
  • @nextrush/types 3.1.0 → (none)
  • @nextrush/validation 1.0.0 → @nextrush/errors, @nextrush/types
  • @nextrush/websocket 1.0.0 → @nextrush/types
  • create-nextrush 1.0.0 → (none) [external: @clack/prompts]
  • nextrush 3.1.0 → @nextrush/adapter-node, @nextrush/class, @nextrush/core, @nextrush/di, @nextrush/errors, @nextrush/router, @nextrush/types [external: reflect-metadata]

Package Size Targets

Each package has a maximum size to keep the framework lean:

PackageMax LOC
@nextrush/types500
@nextrush/errors600
@nextrush/core1,500
@nextrush/router1,000
@nextrush/di400
@nextrush/adapter-*500
@nextrush/middleware/*300
@nextrush/extensions/*600
@nextrush/stream300
@nextrush/openapi600
@nextrush/validation300

@nextrush/class has no fixed LOC ceiling in the current targets — it consolidates what were previously three separately-budgeted packages (decorators, di re-export, controllers).

Common Installation Patterns

Choose the pattern that matches your project needs.

Functional style with direct package imports:

npm install @nextrush/core @nextrush/router @nextrush/adapter-node
import { createApp } from '@nextrush/core';
import { createRouter } from '@nextrush/router';
import { listen } from '@nextrush/adapter-node';

const app = createApp();
const router = createRouter();

router.get('/', (ctx) => ctx.json({ hello: 'world' }));
app.route('/', router);
await listen(app, 8080);

Single package that re-exports all essentials:

npm install nextrush
import { createApp, createRouter, listen } from 'nextrush';

const app = createApp();
const router = createRouter();

router.get('/', (ctx) => ctx.json({ hello: 'world' }));
app.route('/', router);
await listen(app, 8080);

Example stack with security and parsing middleware:

npm install nextrush @nextrush/cors @nextrush/helmet @nextrush/body-parser @nextrush/rate-limit
import { createApp, createRouter, listen } from 'nextrush';
import { cors } from '@nextrush/cors';
import { helmet } from '@nextrush/helmet';
import { json } from '@nextrush/body-parser';
import { rateLimit } from '@nextrush/rate-limit';

const app = createApp();
app.use(cors());
app.use(helmet());
app.use(json());
app.use(rateLimit({ window: '1m', max: 100 }));

const router = createRouter();
router.get('/', (ctx) => ctx.json({ hello: 'world' }));
app.route('/', router);

await listen(app, 8080);

Decorator-based controllers with dependency injection:

npm install nextrush
import { createApp, listen } from 'nextrush';
import { Controller, Get, Service, registerControllers } from 'nextrush/class';

@Service()
class GreetingService {
  greet() {
    return { hello: 'world' };
  }
}

@Controller('/')
class HomeController {
  constructor(private greeting: GreetingService) {}

  @Get()
  index() {
    return this.greeting.greet();
  }
}

const app = createApp();
await registerControllers(app, {
  root: './src',
  prefix: '/api',
});
await listen(app, 8080);

Explore Packages

Was this helpful?

On this page