Backend scaffolding CLI for Node.js with best practices built-in. Generate production-ready Express or Hono projects with TypeScript, authentication, database connections, AI features, and more.
corepack prepare pnpm@11.5.0 --activate
pnpm add -g nod-cli# Create a new project (interactive)
nod init my-api
# Or use shorthand
nod my-api
# Non-interactive default: strict production API (TypeScript by default)
nod init my-api --yes
# One-command AWS SAM backend
nod backend my-api
# Strict SAM backend with shared Postgres rate limits
nod init my-api --preset aws-sam-backend --rate-limit-store postgres --yes
# Or pick a specific preset
nod init my-api --preset 1 --framework express --yes
# Non-interactive with JavaScript
nod init my-api --preset api --no-ts --yes
# Follow the interactive prompts to configure:
# - Preset (production-api, aws-sam-backend, minimal, api, full, ai, 1, or custom presets)
# - Framework (Express/Hono)
# - TypeScript/JavaScript
# - Database (PostgreSQL/MySQL/Supabase/None)
# - ORM (Drizzle/Raw SQL)
# - Authentication (JWT/JWKS/Supabase/Better Auth/None)
# - AI features (RAG, Chat, Langfuse)
# - Deployment (AWS SAM, Vercel cron, GitHub workflow)
# - Rate limit store (Postgres, Redis, None)
# - Docker & PM2 configuration| Preset | Description |
|---|---|
production-api |
Default strict API: Supabase, Drizzle, Better Auth, Postgres-backed rate limits, trusted origins, Lambda/SAM |
aws-sam-backend |
Production AWS SAM backend: Express, TypeScript, Supabase/Drizzle, Better Auth, static Drizzle rate limits, strict security, pnpm dependency layer, Node 22 Lambda |
minimal |
Basic setup, no database or auth |
api |
Standard REST API with JWT auth |
full |
All features including Supabase, Drizzle, Vercel cron |
ai |
Full preset + RAG, Chat, Langfuse |
1 |
Supabase + Drizzle + API Audit + GitHub Actions |
custom |
Choose your own features |
Create and manage your own presets:
# List all presets
nod preset list
# Create a custom preset
nod preset create mystack
# Set default preset
nod preset default mystack
# Show preset details
nod preset show mystack
# Delete a custom preset
nod preset delete mystackCustom presets are stored in ~/.nod-cli/presets.json and can be used like built-in presets:
nod init my-api --preset mystack --yesnod init <project-name>
# or shorthand
nod <project-name>nod backend <project-name>This is shorthand for a production AWS SAM backend preset with Express, TypeScript, strict security, Supabase/Drizzle, Better Auth, Postgres-backed rate limits, a pnpm-built dependency layer, Node.js 22 Lambda, template.yaml, samconfig.toml, and docs/aws-sam-setup.md.
| Option | Description | Default |
|---|---|---|
--framework <framework> |
Web framework: express or hono |
express |
--ts |
Use TypeScript | true |
--no-ts |
Use JavaScript instead of TypeScript | - |
--db <database> |
Database: pg, mysql, supabase, or none |
pg |
--auth <auth> |
Auth: jwt, jwks, supabase, cookie-session, better-auth, or none |
preset |
--queue <queue> |
Queue: bull or none |
none |
--preset <preset> |
Use a preset configuration | production-api in non-interactive mode |
--security <mode> |
Security: basic or strict |
preset |
--deploy-target <target> |
Deploy target: node or lambda-sam |
preset |
--cron <boolean> |
Include node/Lambda cron support | preset |
--vercel-cron <boolean> |
Include Vercel cron config | preset |
--rate-limit-store <store> |
Rate limit store: postgres, redis, or none |
postgres for strict Drizzle/SAM |
-y, --yes |
Skip prompts, use defaults | - |
# Interactive mode
nod init my-api
# TypeScript with preset 1 (non-interactive)
nod my-api --preset 1 --yes
# JavaScript project with API preset
nod init my-api --preset api --no-ts --yes
# Hono framework with Supabase
nod init my-api --framework hono --db supabase --auth supabase --yes
# Minimal JavaScript project
nod my-api --preset minimal --no-ts --yesNavigate to your project directory first:
cd my-apiThen add components:
# Add route with controller and service
nod add route users
# Add complete auth module
nod add auth
# Add shared-store rate limiter (Postgres preferred)
nod add middleware --name rateLimit --type rateLimit --rate-limit-store postgres --yes
# Add Redis-backed rate limiter
nod add middleware --name rateLimit --type rateLimit --rate-limit-store redis --yes
# Add CORS middleware and apply globally
nod add cors
# Add service
nod add service email
# Add cron job support
nod add cron
# Add PM2 configuration
nod add pm2
# Add Vercel cron setup
nod add vercel-cron
# Add GitHub Actions workflow for Vercel deployment
nod add github-actions
# Add RAG service
nod add rag
# Add Chat service
nod add chat
# Add Supabase helper
nod add supabase
# Add Drizzle ORM
nod add drizzle
# Add Langfuse
nod add langfuseAdd nod features to an existing project:
nod transformSelect features to add:
- Environment Config (staging/production)
- Supabase Helper
- Drizzle ORM Setup
- Supabase JWT Auth Middleware
- Vercel Cron Setup
- GitHub Workflow
- RAG Service
- Chat Service
- Langfuse Integration
- Error Handler
- Winston Logger
- Response Formatter
nod preset list # List all presets
nod preset create [name] # Create a new preset
nod preset delete [name] # Delete a custom preset
nod preset default [name] # Set default preset
nod preset show <name> # Show preset detailsnod validateRun a built-in local MCP server over stdio:
nod mcpThis exposes MCP tools:
nod_help- quick command usage examplesnod_run- executenodcommands locally (init/add/transform/validate/preset)
Example Claude Desktop configuration:
{
"mcpServers": {
"nod-cli": {
"command": "nod",
"args": ["mcp"]
}
}
}Generated projects follow this structure:
my-api/
├── src/
│ ├── routes/ # Route definitions
│ ├── controllers/ # Request handlers
│ ├── services/ # Domain services (e.g. user.service.ts)
│ ├── middleware/ # Custom middleware
│ ├── auth/ # Auth services (nod add auth)
│ ├── config/ # App configuration
│ ├── helpers/ # Reusable helpers (e.g. user.helper.ts)
│ ├── utils/ # Utility modules (logger, etc.)
│ ├── db/ # Database connection & schema
│ ├── environments/ # Staging/production configs
│ ├── cron/ # Cron jobs
│ └── types/ # TypeScript types (TS only)
├── docs/ # Project documentation & plans
│ └── README.md # Documentation index
├── temp/ # Temporary output files (git-ignored)
├── sql/ # SQL schema files
├── .github/ # GitHub workflows
├── .env.example # Environment variables template
├── .gitignore
├── package.json
├── tsconfig.json # TypeScript config (TS only)
├── tsconfig.build.json # TypeScript emit config for non-SAM TS projects
├── tsconfig.lambda.json # TypeScript emit config for SAM TS projects
├── scripts/ # SAM build and runtime import checks (AWS SAM backend)
├── drizzle.config.ts # Drizzle config (if using Drizzle)
├── template.yaml # AWS SAM template (if using AWS SAM)
├── samconfig.toml # AWS SAM deploy profiles (if using AWS SAM)
├── vercel.json # Vercel config (if using Vercel cron)
├── Dockerfile # Docker config (if enabled)
├── docker-compose.yml # Docker Compose (if enabled)
├── ecosystem.config.js # PM2 config (if enabled)
└── README.md # Project README
| Folder | Purpose |
|---|---|
docs/ |
Project documentation, architecture decisions, API docs, and development plans. Committed to git. |
temp/ |
Temporary output files (PDFs, exports, generated files). Git-ignored. |
| Option | Choices | Description |
|---|---|---|
| Framework | Express, Hono | Web framework |
| TypeScript | Yes, No | Type safety (use --no-ts for JavaScript) |
| Database | PostgreSQL, MySQL, Supabase, None | Database driver |
| ORM | Drizzle, Raw SQL, None | ORM choice |
| Auth | JWT, JWKS, Supabase, None | Authentication method |
| Cron | Yes, No | Scheduled jobs support |
| Environments | Yes, No | Staging/production config |
| RAG | Yes, No | Vector search & retrieval |
| Chat | Yes, No | Conversation management |
| Langfuse | Yes, No | LLM observability |
| Vercel Cron | Yes, No | Vercel cron configuration |
| Rate Limit Store | Postgres, Redis, None | Shared rate-limit storage |
| GitHub Workflow | Yes, No | CI/CD workflow |
| Docker | Yes, No | Container configuration |
| PM2 | Yes, No | Process manager config |
- Declarative Routes - Clean, configuration-based route definitions
- Type Safety - Full TypeScript support (or plain JavaScript with
--no-ts) - PM2 Cluster Mode - Thread-safe cron jobs with distributed locking
- Shared Rate Limits - Postgres/Drizzle by default, Redis when selected
- Docker Ready - Dockerfile and docker-compose included
- Zod Validation - Runtime config validation (TypeScript only)
- Documentation Folder - Built-in
docs/folder for project documentation - Temp Output Folder - Git-ignored
temp/folder for generated files
- Supabase Integration - Full Supabase client with storage helpers
- Drizzle ORM - Type-safe ORM with connection pooler support
- Environment Config - Separate staging/production configurations
- Complete Auth Module -
nod add authgenerates JWKS, JWT, password hashing, Google OAuth, forgot password, email service - Supabase JWT Auth - JWKS-based JWT verification using jose library
- Custom JWT - Roll your own tokens with auto-generated RSA keys
- Password Hashing - Bcrypt-based password hashing with strength validation
- Google OAuth - Server-side token verification
- Permission Middleware - Role-based access control from JWT payload
- RAG Service - Vector similarity search with OpenAI embeddings
- Chat Service - Conversation management with LangChain
- Langfuse - Optional LLM observability and tracing
- AWS SAM - Lambda/API Gateway backend with TypeScript ESM
.jsemit and a pnpm-built dependency layer - Vercel Cron - Cron job configuration with auth middleware
- GitHub Workflow - Deploy trigger workflow
Generated SAM backends use ESM .js files under "type": "module". They do not emit .mjs.
The Lambda build is deliberately split:
dist/contains TypeScript-emitted application code and Lambda handlers.dist-layer/contains productionnode_modulesinstalled with pnpm.template.yamlattaches the dependency layer to every function and usesBuildMethod: makefile.scripts/check-sam-runtime-imports.jsimports every built handler aftersam build --parallel.
This avoids standalone bundler failures from hidden dynamic imports such as packages that compute import('drizzle-orm') at runtime. Postgres rate limits use generated static Drizzle SQL instead of rate-limiter-flexible's Drizzle adapter. Redis rate limits still use rate-limiter-flexible.
Generated Drizzle clients are Lambda-safe by default: prepare: false, DATABASE_POOL_MAX=2, DATABASE_CONNECT_TIMEOUT_SECONDS=5, DATABASE_IDLE_TIMEOUT_SECONDS=20, and DATABASE_MAX_LIFETIME_SECONDS=1800. Use an RDS Proxy or database pooler URL for Lambda.
Generated API audit middleware skips GET, HEAD, and OPTIONS DB writes. Use ALB/API Gateway/WAF/access logs for read-path traffic and keep DB audit rows for mutations or explicit domain events.
cd my-api
pnpm install
cp .env.example .env
# Edit .env with your settings
pnpm dev| Script | Description |
|---|---|
pnpm dev |
Start development server with hot reload |
pnpm build |
Build for production (TypeScript only) |
pnpm start |
Start production server |
pnpm lint |
Lint code with ESLint |
pnpm format |
Format code with Prettier |
pnpm test |
Run tests (if testing enabled) |
pnpm build
pm2 start ecosystem.config.jspnpm start:pm2 # Start with PM2
pnpm stop:pm2 # Stop PM2 processes
pnpm restart:pm2 # Restart PM2 processes
pnpm logs:pm2 # View PM2 logs
pnpm monit:pm2 # Monitor PM2 processespnpm db:generate # Generate migrations
pnpm db:migrate # Apply migrations
pnpm exec drizzle-kit migrate --config=<drizzle.config.ts|drizzle.config.js> # Apply migrations
pnpm db:studio # Open Drizzle StudioFor CI/CD pipelines, use the --yes flag to skip all prompts:
# In CI environment
nod init my-api --preset api --yes
# With specific options
nod init my-api --preset 1 --framework express --no-ts --yesThe CLI also respects the CI environment variable - when CI=true, it automatically uses non-interactive mode.
MIT