Quick Start
Scaffold a runnable NextRush project in one command — npm create nextrush, cd, npm run dev. Pick a style, a middleware preset, and a runtime, and skip the manual setup from Installation.
Quick Start · Scaffold
Go from zero to a running API in under 2 minutes.
One command. No manual setup — tsconfig.json, scripts, a sample route, and a real unit test
are all generated.
✓ Generated
✓ Running
✓ Tested
Wiring a project by hand teaches how the pieces fit — that's what Installation and the Task API tutorial are for. Once you've done that once, use this page to skip straight to running: it picks a style, a middleware preset, and a runtime for you.
Outcome
What you'll build
A new folder that runs with pnpm dev and ships a real unit test — everything wired for you:
Setup · 3 steps
Create the project
The scaffolder is the npm package create-nextrush. Your package manager can invoke it several
ways:
$ pnpm create nextrush@latest my-api
my-api is the target directory — pass . to scaffold into the current folder, or omit it to be
prompted. The flow is built on @clack/prompts.
Install dependencies
The scaffolder installs for you by default — this step is usually a no-op. Only if you skipped install, or want to re-run it:
cd my-api
pnpm installRun it
cd my-api
pnpm dev # hot-reload dev server🎉 You're ready — verify it works
Your app should be live on http://localhost:8080. Confirm it:
curl http://localhost:8080/
# → {"message":"Welcome to NextRush!"}
curl http://localhost:8080/health
# → {"status":"ok","timestamp":"…","uptime":…}Expected: a Welcome to NextRush! JSON body on / and an ok status on /health. Class-based
projects answer on /api/health instead of /health.
Your NextRush app is running. Everything is working correctly.
Recommended next
Build your first API
Further Reading
Your app is running. Want to understand what's happening under the hood? These explain the scaffold, project structure, CLI flags, and common pitfalls.
Six prompts, every one with a default — press Enter to accept.
Project name
Where to create the project. Defaults to my-nextrush-app if you didn't pass a directory.
The scaffolder derives package.json's name from this path — invalid characters become
hyphens, so My API! becomes my-api.
Style
Three choices. Functional is the default — the smallest surface.
Functional (default)
Routes only, no decorators. Smallest surface — best for small APIs and microservices.
Class-based
Controllers, DI, and decorators. Routes register under /api. Best when you want structure from day one.
Full
Both styles side by side. A reference layout showing functional routes and class-based controllers together.
Full comparison with generated trees and code: Project structure.
Runtime
Node.js (default)
No adapter needed — nextrush re-exports @nextrush/adapter-node.
Bun
Adds @nextrush/adapter-bun and swaps the generated import and scripts.
Deno
Adds @nextrush/adapter-deno and swaps the generated import and scripts.
Edge and serverless aren't scaffolder targets — Edge and Serverless are paths you follow manually once a project exists.
Middleware preset
Minimal
No middleware — core only.
API (default)
cors, body-parser, helmet. Registered in production-safe order.
Full
API preset + rate-limit, compression, request-id.
The scaffolder writes the matching import lines and app.use(...) calls into src/index.ts.
Install dependencies?
Defaults to yes. Say no to scaffold files only and run pnpm install yourself afterward.
Initialize git?
Defaults to yes — git init plus an initial commit. Say no to skip.
Every prompt has a matching flag. A fully-specified command never pauses:
pnpm create nextrush@latest my-api --style functional --runtime node --middleware apipnpm create nextrush@latest my-bun-api --style functional --runtime bun --middleware fullpnpm create nextrush@latest my-deno-api --style class-based --runtime deno --middleware api-y / --yes accepts every default without specifying each option:
pnpm create nextrush@latest my-api --yesScaffold without install or git:
pnpm create nextrush@latest my-api --yes --no-install --no-gitcreate-nextrush flags
| Property | Type | Description |
|---|---|---|
--style, -s | "functional" | "class-based" | "full"= "functional" | Project style |
--runtime, -r | "node" | "bun" | "deno"= "node" | Target runtime for the generated project |
--middleware, -m | "minimal" | "api" | "full"= "api" | Middleware preset |
--pm | "npm" | "pnpm" | "yarn" | "bun"= auto-detected from how you invoked the scaffolder; "bun" if --runtime bun | Package manager for install and generated scripts |
--install, -i | boolean= true | Install dependencies |
--no-install | boolean | Skip dependency installation |
--git | boolean= true | Initialize a git repository |
--no-git | boolean | Skip git initialization |
-y, --yes | boolean= false | Accept every default, skipping all interactive prompts |
-v, --version | boolean | Print the installed create-nextrush version |
-h, --help | boolean | Print flag usage |
The project name comes from the directory you pass — invalid characters become hyphens, so
My API! becomes my-api. Passing . names the project after the current folder.
Every style shares tsconfig.json, package.json, README.md, .gitignore, and src/env.d.ts
for editor hints — then adds its own source layout. Each ships at least one real vitest unit
test, not a placeholder.
Best for: Small to mid-size APIs, microservices, minimal surface area — without sacrificing a professional layered structure.
A production-grade layered API: routes → services → repositories, with centralized config, shared domain types, and custom middleware. No classes, decorators, or DI — pure factory functions throughout.
The entrypoint uses the framework's built-in errorHandler from nextrush (first in the
middleware chain). Services throw NotFoundError/BadRequestError from nextrush; routes
stay free of try/catch:
import { createApp, createRouter, errorHandler, listen } from 'nextrush';
import { cors } from '@nextrush/cors';
import { json } from '@nextrush/body-parser';
import { helmet } from '@nextrush/helmet';
import { config } from './config/index.js';
import { logger } from './middleware/logger.js';
import { healthRouter } from './routes/health.routes.js';
const router = createRouter();
const app = createApp({ router });
// Error handling (first middleware — catches all downstream errors)
app.use(errorHandler({ includeStack: config.nodeEnv !== 'production' }));
// Request logging
app.use(logger());
// Middleware
app.use(cors());
app.use(helmet());
app.use(json());
// Routes
router.get('/', (ctx) => {
ctx.json({ message: 'Welcome to NextRush!' });
});
app.route('/health', healthRouter);
await listen(app, config.port);import { BadRequestError, NotFoundError } from 'nextrush';
import type { TodoRepository } from '../repositories/todos.repository.js';
export function createTodoService(repository: TodoRepository) {
return {
get(id: string) {
const todo = repository.findById(id);
if (!todo) throw new NotFoundError('Todo not found');
return todo;
},
// ...create, list, remove
};
}Health lives at GET /health. On Bun or Deno, listen comes from @nextrush/adapter-bun
or @nextrush/adapter-deno instead. Deno reads Deno.env.get('PORT') in config/index.ts.
Best for: DI, decorators, structured architecture from day one.
The root AppModule composes feature modules via @Module({ imports }), and the entry file wires
the whole graph in one call:
import { createApp, createRouter, listen } from 'nextrush';
import { registerModule } from 'nextrush/class';
import { AppModule } from './app.module.js';
const router = createRouter();
const app = createApp({ router });
// Wire the root module — registers the whole module graph in one call
await registerModule(app, AppModule, { prefix: '/api' });
await listen(app, PORT);import { Controller, Get } from 'nextrush/class';
import { HealthService } from './health.service.js';
@Controller('/health')
export class HealthController {
constructor(private readonly health: HealthService) {}
@Get()
check() {
return this.health.getHealth();
}
}Health lives at GET /api/health — the /api prefix comes from registerModule, not the
controller decorator alone.
Choosing class-based enables experimentalDecorators and emitDecoratorMetadata in
tsconfig.json, and adds reflect-metadata plus @nextrush/class as explicit dependencies — same
requirement as Installation's TypeScript step.
Best for: Both routing styles in one service. A reference layout.
full combines a functional /health route with a class-based module graph (@Module/AppModule
via registerModule, the same standard as the class-based style) and error-handler.ts registered
first in the middleware chain. Controllers mount under the /api prefix through the root
module.
Useful as a reference when you want both routing styles in one service — not the smallest starting point.
Generated scripts reference
package.json scripts differ by runtime. Every style also includes "test": "vitest run".
| Runtime | dev | build | start | test |
|---|---|---|---|---|
node | nextrush dev | nextrush build | node dist/index.js | vitest run |
bun | bun nextrush dev | bun nextrush build | bun dist/index.js | vitest run |
deno | deno run … npm:nextrush dev | deno run … npm:nextrush build | deno run --allow-net --allow-read --allow-env dist/index.js | vitest run |
Deno's dev/build scripts route through nextrush dev and nextrush build (not a raw
deno run on the entry file) so decorator metadata stays consistent with Node and Bun. The
--allow-* flags are Deno's permission model — see Deno onboarding.
Wrong package name with dlx/npx
- Symptom:
- Package not found when running pnpm dlx create nextrush
- Cause:
- Direct invocations need the hyphenated npm name, not the create-space form
✅ Fix: Use pnpm dlx create-nextrush or npx create-nextrush@latest
Old scaffold despite publishing a new version
- Symptom:
- The generated project has a flat src/routes/ layout with no services/, repositories/, or config/ — even though the scaffolder was just updated
- Cause:
- pnpm 11.x (and Deno's npm: compatibility) can resolve @latest to an old cached version for packages with a version gap — a known resolution bug (pnpm#8659), not a problem with create-nextrush
✅ Fix: Use npm create nextrush or bun create nextrush, which resolve @latest correctly — or use pnpm@10
Looking for /health on a class-based project
- Symptom:
- 404 on GET /health after scaffolding class-based or full
- Cause:
- Controllers register under the /api prefix
✅ Fix: Try GET /api/health — or scaffold functional if you want /health at the root
Git or install step failed
- Symptom:
- CLI prints failed - see the error above but files exist on disk
- Cause:
- Missing git on PATH, network blocked during install, or permission error
✅ Fix: Files are already written — retry git init or pnpm install manually
Scaffolding into a non-empty directory
- Symptom:
- CLI asks for confirmation before overwriting
- Cause:
- Target folder already has files
✅ Fix: Confirm only if you mean to merge, or pass a fresh directory name
Use npm create nextrush or bun create nextrush — pnpm create nextrush (bare) and
deno run -A npm:create-nextrush@latest can resolve @latest to an old cached version
on pnpm 11.x and Deno (a known resolution bug, pnpm#8659).
Direct invocations (npx, pnpm dlx, bunx) need the hyphenated package name:
create-nextrush, not create nextrush.
What's next
Continue learning
You have a running app — now make it yours. Each of these picks up exactly where the scaffolder left off:
⭐ Task API Tutorial
Hand-wire create, read, and honest 404s to learn the request pipeline. ~40 min · beginner
Class-based controllers
Build on class-based or full with guards, DI, and decorators. intermediate
Dev tools
Hot reload, production builds, and generator commands.
Runtimes
What changes on Bun, Deno, edge, and serverless once your project exists.