Scaffold with create-nextrush
Generate a runnable NextRush project with one command — pick a style, a middleware preset, and a runtime, and skip the manual setup from Installation.
Start · Scaffold
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, create-nextrush generates the same foundation in one command:
tsconfig.json, scripts, middleware wiring, a sample route or controller, and a real unit test.
✓ Functional, class-based, or full layout
✓ Node, Bun, or Deno scripts
✓ Middleware preset wired for you
✓ Runnable + testable out of the box
What you'll have
By the end, a new folder runs with pnpm dev (or your package manager's equivalent):
Prerequisites
CLI runtime
Node.js 22+ — the scaffolder itself runs on Node
Package manager
pnpm, npm, yarn, or bun
When to scaffold
New project — not adding one package to an existing app
Prefer wiring every file yourself first? Start with Installation or the Task API tutorial, then come back here for your second project.
Run it
The scaffolder is the npm package create-nextrush. Your package manager can invoke it several
ways:
$ pnpm create nextrush my-api
create nextrush vs. create-nextrush
pnpm create nextrush and npm create nextrush use a space — your package manager expands
create <name> to the npm package create-<name>, so nextrush resolves to create-nextrush.
Calling the package directly (npx, pnpm dlx, bunx) needs the hyphenated name:
pnpm dlx create-nextrush, not pnpm dlx create nextrush.
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.
How it works
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 styles.
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
The runtime prompt only offers Node, Bun, and Deno. 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.
Skip the prompts
Every prompt has a matching flag. A fully-specified command never pauses:
pnpm create nextrush my-api --style functional --runtime node --middleware apipnpm create nextrush my-bun-api --style functional --runtime bun --middleware fullpnpm create nextrush my-deno-api --style class-based --runtime deno --middleware api-y / --yes accepts every default without specifying each option:
pnpm create nextrush my-api --yesScaffold without install or git:
pnpm create nextrush my-api --yes --no-install --no-gitAll CLI flags
create-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.
Project styles
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 APIs, microservices, minimal surface area.
health-status.ts holds a pure function the route calls — testable without spinning up HTTP.
import { createApp, createRouter, listen } from 'nextrush';
import { cors } from '@nextrush/cors';
import { json } from '@nextrush/body-parser';
import { helmet } from '@nextrush/helmet';
import { healthRouter } from './routes/health.js';
const router = createRouter();
const app = createApp({ router });
const PORT = Number(process.env.PORT) || 8080;
// 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, PORT);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') for the port line.
Best for: DI, decorators, structured architecture from day one.
Controllers are auto-discovered — no manual mount list:
import { createApp, createRouter, listen } from 'nextrush';
import { registerControllers } from 'nextrush/class';
const router = createRouter();
const app = createApp({ router });
await registerControllers(app, {
root: CONTROLLERS_ROOT,
include: CONTROLLERS_INCLUDE,
prefix: '/api',
strict: true,
});
await listen(app, PORT);import { Controller, Get } from 'nextrush/class';
import { AppService } from '../services/app.service.js';
@Controller('/health')
export class HealthController {
constructor(private readonly appService: AppService) {}
@Get()
check() {
return this.appService.getHealth();
}
}Health lives at GET /api/health — the /api prefix comes from registerControllers, 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, class-based /api/hello controllers, and
error-handler.ts registered first in the middleware chain. The entry file uses serve()
instead of listen() so startup can log the bound port.
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.
After scaffolding
cd my-api
pnpm dev # hot-reload dev server
pnpm test # run the generated unit test(s)
pnpm build # production build
pnpm start # run the production buildVerify the server (functional style, default middleware):
curl http://localhost:8080/
# → {"message":"Welcome to NextRush!"}
curl http://localhost:8080/health
# → {"status":"ok","timestamp":"…","uptime":…}Class-based projects answer on /api/health instead of /health.
Code generators
Once the project exists, nextrush generate (alias nextrush g) adds controllers, services,
middleware, guards, and routes — see the generators guide.
Common mistakes
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
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
What you learned
- ✓ Invoke the scaffolder with your package manager — pnpm, bun, npm, or yarn
- ✓ Three project styles: Functional (smallest), Class-based (structured), Full (both)
- ✓ Runtime selection changes the adapter import and scripts — Node, Bun, or Deno
- ✓ Middleware presets wire
cors,body-parser,helmet(API) +rate-limit,compression,request-id(Full) in production-safe order - ✓ Every style ships at least one real
vitestunit test, not a placeholder
Scaffold completeYour project is generated, dependencies installed, and a real test is passing. Run pnpm dev to start the server.
Next steps
⭐ Build a Task API — recommended if you skipped the tutorial
Hand-wire create, read, and honest 404s to learn the request pipeline.
Class-based controllers
Build on class-based or full with guards, DI, and decorators.
Dev tools
Hot reload, production builds, and generator commands.
Runtimes
What changes on Bun, Deno, edge, and serverless once your project exists.
Build a Task API
Build a Task API from an empty folder to a running server, and learn the request pipeline every NextRush app shares — routing, middleware order, context, and errors — along the way.
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.