Core Concepts
The mental models that make NextRush predictable and composable
Before you write code, understand how NextRush thinks.
These are the core abstractions that determine how your application processes requests, composes behavior, and handles failure.
The Four Pillars
NextRush is built on four core abstractions. Everything else builds on top of these.
Application
Your entry point. Orchestrates middleware, extensions, and error handling.
Context
The ctx object. Your unified interface to request and response.
Middleware
Functions that process requests. The onion model for composable logic.
Routing
Segment trie routing. O(k) lookup regardless of route count.
How They Work Together
When a request arrives, it flows through a predictable pipeline:
HTTP Request
↓
┌─────────────────────────────┐
│ Application │
│ ┌───────────────────────┐ │
│ │ Middleware Pipeline │ │
│ │ ┌─────────────────┐ │ │
│ │ │ cors → auth │ │ │
│ │ │ ↓ │ │ │
│ │ │ body-parser │ │ │
│ │ │ ↓ │ │ │
│ │ │ router │ │ │
│ │ └─────────────────┘ │ │
│ └───────────────────────┘ │
│ ↓ │
│ ┌───────────────────────┐ │
│ │ Router │ │
│ │ Match path → Handler │ │
│ └───────────────────────┘ │
└─────────────────────────────┘
↓
HTTP ResponseThe flow is always the same:
- Request arrives at the adapter
- Adapter creates a fresh Context object
- Application passes context through Middleware
- Router matches the path and extracts params
- Handler executes and writes to context
- Response flows back through middleware
- Adapter sends the HTTP response
Context is Per-Request
Every request gets a new ctx object. There's no shared state between requests unless you
explicitly create it.
Two Programming Styles
NextRush supports both functional and class-based programming. Choose based on your project's needs.
Simple, direct, minimal abstraction. Often fits small services and APIs.
import { createApp, createRouter } from 'nextrush';
const app = createApp();
const router = createRouter();
router.get('/users/:id', async (ctx) => {
const user = await db.users.findById(ctx.params.id);
ctx.json({ user });
});
app.route('/api', router);Structured, with dependency injection. Often fits larger applications and shared codebases.
import { createApp } from 'nextrush';
import { Controller, Get, Param, Service, registerControllers } from 'nextrush/class';
@Service()
class UserService {
async findById(id: string) {
return db.users.findById(id);
}
}
@Controller('/users')
class UserController {
constructor(private users: UserService) {}
@Get('/:id')
async getUser(@Param('id') id: string) {
return { user: await this.users.findById(id) };
}
}
const app = createApp();
await registerControllers(app, { root: './src' });You Can Mix Styles
Both styles work together. Start with functions, add classes when you need structure. There's no forced migration.
Extension Points
Beyond the four pillars, NextRush provides three ways to extend functionality — unequal in weight. Reach for middleware first; it covers nearly everything.
Middleware (the default, ~99%)
Almost every capability — security, parsing, logging, docs — is added with app.use():
import { openapi } from '@nextrush/openapi';
app.use(openapi({ router: app.router!, info: { title: 'API', version: '1.0.0' } }));Registrar (~0.9%)
A plain function you call directly to wire up a subsystem, like class-based controllers:
import { registerControllers } from 'nextrush/class';
await registerControllers(app, { root: './src' });Extension (~0.1%, rare)
For long-lived, app-scoped services that need a boot phase and a teardown phase — reserved for framework-level infrastructure like the event bus:
import { events } from '@nextrush/events';
app.extend(events());
await app.ready();Guards
Control access to routes declaratively:
@UseGuard(AuthGuard)
@UseGuard(RoleGuard('admin'))
@Controller('/admin')
class AdminController {
@Get('/dashboard')
dashboard() {
return { admin: true };
}
}The Class Runtime's Deeper Subsystems
Once an application grows past a handful of controllers, nextrush/class provides four more subsystems for structuring larger codebases. Each builds on dependency injection, which itself is worth understanding first.
Dependency Injection & Scopes
Singleton, transient, and request scope — and how request scope bubbles through a dependency graph.
Modules
Group a feature's controllers and providers behind one declaration, and compose features with imports.
Interceptors
Wrap a controller method to transform its result, time it, or return a cached value.
Exception Filters
Localize error handling to a specific controller or route.
Lifecycle Hooks
Run initialization and cleanup on a DI-managed service with OnInit and OnShutdown.
What You Should Learn First
Context API
Understand the ctx object—it's your primary interface for everything. Read Context →
Middleware
Learn the onion model. It determines execution order and error handling. Read Middleware →
Routing
Map URLs to handlers efficiently with segment trie routing. Read Routing →
Mental Model Summary
| Concept | Responsibility | Key Insight |
|---|---|---|
| Application | Orchestration | Holds everything together, manages lifecycle |
| Context | Request/Response | Fresh per-request, mutable state for sharing |
| Middleware | Transformation | Onion model—before, next(), after |
| Routing | URL Matching | O(k) segment trie, params and wildcards |
| Extending | Capability | Middleware (~99%), Registrar (~0.9%), Extension (~0.1%) |
| Guards | Access Control | Boolean gatekeepers for routes |
The class runtime's deeper subsystems build on top of these:
| Concept | Responsibility | Key Insight |
|---|---|---|
| DI & Scopes | Object Lifetime | Singleton / transient / request, with bubbling |
| Modules | Composition | Group controllers + providers, compose via imports |
| Interceptors | Result Shaping | Onion around a controller method's return value |
| Exception Filters | Error Scoping | Localized catch blocks per controller/route |
| Lifecycle | Boot/Shutdown | OnInit/OnShutdown, duck-typed, no decorator |
Common Misconception
Middleware order matters. Error handlers must come first. Body parsers must run before you access
ctx.body. If something isn't working, check your registration order.
Next Steps
Application
The entry point that orchestrates everything.
Context
Your interface to request and response.
Middleware
The pipeline that processes every request.
Routing
Segment-trie URL matching.
Extending NextRush
Middleware, Registrar, and Extension — the three ways to add capability.
Guards
Declarative access control.
Ready to structure a larger application? Continue into the class runtime's deeper subsystems:
Benchmarks
NextRush v3 performance dashboard — head-to-head HTTP throughput vs Fastify, Hono, Koa, Express, and a raw Node.js baseline. Interactive charts, heatmap, scenario explorer, and reproducible methodology.
Application
How createApp() gives every NextRush server one composition root — the object that owns middleware, routes, extensions, and the boot/shutdown lifecycle.