/SKILL.md
Guides AI agents to scaffold and develop production-grade Node.js + Express backends with a clean, scalable folder structure and industry best practices. Use when user asks to "create a backend", "set up an API", "scaffold a Node project", "build an Express server", "create REST API", "backend folder structure", "API boilerplate", or starts a new Node.js/Express backend project. Covers JS and TS.
npx skillsauth add codewithhashim/express-backend-starter-skill express-backend-starterInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert guidance for building production-grade, API-only Node.js + Express backends. This skill ensures every new backend project starts with a clean architecture, consistent patterns, and security-first defaults — whether in JavaScript or TypeScript.
Before writing any code, clarify with the user:
If the user doesn't specify, default to: TypeScript + PostgreSQL + Prisma + JWT.
Node Version: Require Node 24 LTS (Active LTS), preferably >=24.10.0 for non-experimental env-file support. Use node --watch for dev restarts and --env-file-if-exists for env loading — no nodemon or dotenv needed. For the full version/stability table and lifecycle guidance, see node-version-guide.md.
Pin the Node version in .nvmrc — e.g. 24 or a specific 24.x.y (>=24.10.0 recommended).
Always generate this folder structure. Adapt file extensions based on JS vs TS.
.
├─ src/
│ ├─ app/
│ │ ├─ app.(js|ts) # Express app: middleware stack + route mounting
│ │ └─ server.(js|ts) # HTTP server start + graceful shutdown
│ ├─ config/
│ │ ├─ env.(js|ts) # Env var parsing + validation (fail fast on boot)
│ │ └─ index.(js|ts) # Normalized config object (single source of truth)
│ ├─ routes/
│ │ ├─ index.(js|ts) # Mount all versioned routers (e.g. /api/v1)
│ │ └─ v1/
│ │ ├─ health.routes.(js|ts) # Health + readiness endpoints
│ │ └─ users.routes.(js|ts) # Example resource module
│ ├─ controllers/
│ │ └─ users.controller.(js|ts) # HTTP glue only (thin — no business logic)
│ ├─ services/
│ │ └─ users.service.(js|ts) # All business logic and use-cases
│ ├─ repositories/
│ │ └─ users.repo.(js|ts) # DB access only (queries, ORM calls)
│ ├─ db/
│ │ ├─ client.(js|ts) # DB connection pool / Prisma client
│ │ ├─ migrations/ # Database migration files
│ │ └─ seed/ # Seed scripts for dev/test data
│ ├─ middlewares/
│ │ ├─ auth.(js|ts) # Authentication middleware
│ │ ├─ error-handler.(js|ts) # Global error handler (MUST be last middleware)
│ │ ├─ rate-limit.(js|ts) # Rate limiting (global + per-route)
│ │ └─ request-id.(js|ts) # Adds req.id for log correlation
│ ├─ validators/
│ │ └─ users.schema.(js|ts) # Zod or Joi schemas for request validation
│ ├─ errors/
│ │ ├─ AppError.(js|ts) # Custom error base class with status + code
│ │ └─ error-codes.(js|ts) # Stable, documented error codes map
│ ├─ logging/
│ │ └─ logger.(js|ts) # Structured logger (pino/winston) + secret redaction
│ ├─ utils/
│ │ ├─ async-handler.(js|ts) # Wraps async controllers (no try/catch boilerplate)
│ │ └─ http-response.(js|ts) # Standardized success/error response helpers
│ └─ types/ # TS only: shared interfaces and type definitions
│
├─ tests/
│ ├─ unit/ # Service + utility unit tests
│ ├─ integration/ # Route + DB integration tests
│ └─ e2e/ # Full flow end-to-end tests
│
├─ docs/
│ ├─ openapi.yaml # OpenAPI spec (recommended)
│ └─ runbook.md # Deploy, rollback, and ops notes
│
├─ scripts/ # One-off scripts (backfills, maintenance)
├─ docker/ # Dockerfile, docker-compose, local infra
├─ .github/workflows/ # CI pipeline config
├─ .env.example # Documented env var template
├─ .editorconfig
├─ .nvmrc # Pin Node version
├─ .eslintrc.* / eslint.config.*
├─ .prettierrc / prettier.config.*
├─ README.md
└─ package.json
CRITICAL rules:
dist/ folder; never run raw .ts in production.routes → controller → service → repository → validator.types/ for TS-only shared interfaces; omit for JS repos.All requests MUST flow through these layers in order:
Route → Controller → Service → Repository
| Layer | Responsibility | Rules | |---|---|---| | Routes | Define URL paths + HTTP methods | Only call controllers. No logic. | | Controllers | Parse/validate input, call service, format response | THIN — no business logic, no DB calls | | Services | Business logic, permissions, orchestration | May call multiple repos. Owns transactions. | | Repositories | Database queries only | Return domain objects, not raw DB rows |
NEVER skip layers. Controllers must NOT call repositories directly. Services must NOT write raw SQL.
Every backend MUST include these from day one:
* in production)Mount middleware in this exact order:
request-id — assigns unique ID to every requesthelmet — security headerscors — cross-origin policyexpress.json(), express.urlencoded()) + size limits/api/v1/*Use a consistent response shape across ALL endpoints:
// Success
{
"success": true,
"data": { ... }
}
// Error
{
"success": false,
"error": {
"code": "USER_NOT_FOUND",
"message": "No user found with the given ID.",
"details": null
}
}
Use correct HTTP status codes:
400 — validation errors401 — unauthenticated403 — forbidden (authenticated but not authorized)404 — resource not found409 — conflict (duplicate, etc.)429 — rate limited500+ — server errorsAppError class extending Error with statusCode, code, and isOperational properties.async-handler wrapper for all controller methods to catch rejected promises automatically.AppError → return structured error with the appropriate status.error-codes.(js|ts) — clients depend on these, not message strings.pino recommended, winston acceptable).req.id (request ID) to every log entry for correlation.x-request-id.GET /api/v1/health — always returns 200 if process is alive.GET /api/v1/ready — checks DB and external service connectivity.Environment:
src/config/index.(js|ts) — NEVER scatter process.env.* across the codebase..env.example documenting every required and optional variable.dotenv — use Node's built-in env loading instead.Package.json scripts depend on your Node version. See scripts-and-env.md for the full 3-tier guide (Tier A: Node >=24.10.0 non-experimental, Tier B: Node 22.9+ experimental flags, Tier C: Node 20.12+ programmatic loading).
Quick reference (Tier A / recommended):
node --watch --env-file-if-exists=.env src/app/server.jstsc -w in terminal 1, node --watch --env-file-if-exists=.env dist/app/server.js in terminal 2Always include: lint, format, test, test:watch, migrate, seed
IMPORTANT: Do NOT add nodemon, dotenv, or tsx as dependencies.
repositories/ — services never write raw queries.src/db/seed/ for reproducible dev/test data.tests/unit/) — test services, utilities, and pure logic in isolation.tests/integration/) — test routes with a real DB (use Docker).tests/e2e/) — test complete user flows end-to-end.supertest for HTTP assertions in integration tests.vitest (preferred) or jest.node --test) is stable since Node 20 and supports describe/it and assertions. Module mocking requires --experimental-test-module-mocks; coverage via --experimental-test-coverage. Vitest and Jest remain excellent for richer ecosystems.Before deploying, ensure:
/api/v1/health..env files.| Type | Pattern | Example |
|---|---|---|
| Routes | *.routes.(js\|ts) | users.routes.ts |
| Controllers | *.controller.(js\|ts) | users.controller.ts |
| Services | *.service.(js\|ts) | users.service.ts |
| Repositories | *.repo.(js\|ts) | users.repo.ts |
| Validators | *.schema.(js\|ts) | users.schema.ts |
| Errors | AppError.(js\|ts) | AppError.ts |
| Config | Descriptive names | env.ts, index.ts |
Runtime:
express — web frameworkhelmet — secure headerscors — cross-origin requestszod or joi — request validationpino or winston — structured loggingpg, mysql2, mongoose, or prismaNOT needed (handled by Node.js built-ins):
dotenv~~ — use --env-file-if-exists (non-experimental in Node >=24.10.0) or process.loadEnvFile() (Node >=20.12.0)nodemon~~ — use node --watch (stable since Node >=20.13.0)tsx~~ — use tsc -w + node --watch (or native TS in Node >=22.18.0)Dev tooling:
eslint + prettier — code qualityvitest or jest — test runner (or node --test for zero-dependency testing; coverage via --experimental-test-coverage)supertest — HTTP integration testinghusky + lint-staged — git hooks (optional but recommended)typescript — compiler (TS repos only)User says: "Create a new Express API for a task management app"
Actions:
tasks as the first resource moduleroutes/v1/tasks.routes.ts, controllers/tasks.controller.ts, services/tasks.service.ts, repositories/tasks.repo.ts, validators/tasks.schema.tspackage.json with node --watch dev script and --env-file-if-exists for env loading — no nodemon or dotenv.env.example24 in .nvmrc (Node 24 LTS)User says: "Add an orders feature to my API"
Actions:
routes/v1/orders.routes.(js|ts)controllers/orders.controller.(js|ts)services/orders.service.(js|ts)repositories/orders.repo.(js|ts)validators/orders.schema.(js|ts)routes/v1/ indexUser says: "Review my Express backend structure"
Actions:
package.json scripts based on Node version.--env-file-if-exists.development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.