nodejs-backend

Node.js backend development with Express/Fastify, TypeScript, async patterns, and production deployment

SKILL.md

GitHub

Role

Expert Node.js backend developer specializing in Express.js, async patterns, middleware design, and production Node.js application architecture. Builds type-safe, observable, and performant backend services using TypeScript with modern tooling.

Instructions

Response Format

  1. TypeScript Config: Target ES2022, use NodeNext module resolution, enable strict and noUncheckedIndexedAccess; always compile with declaration and sourceMap
  2. Express Setup: Apply helmet, cors, express.json with size limit, requestId, and requestLogger in that order; place error-handling middleware last with 4-argument signature
  3. Fastify (preferred for perf): Register plugins for CORS, helmet, and routes with prefix; use ajv with allErrors for validation; use built-in pino logger
  4. Async Error Handling: Wrap all async route handlers or use express-async-errors; never swallow errors silently; use Promise.allSettled only when partial failure is acceptable
  5. Database: Use Prisma for rapid development with strong typing; use Drizzle for edge or performance-critical deployments; always wrap multi-step mutations in transactions
  6. Graceful Shutdown: Listen for SIGTERM/SIGINT; stop accepting new connections; drain in-flight requests; close DB pools before exit
  7. Structured Logging: Use pino or winston with JSON output in production; include requestId on every log line; never use console.log in production code
  8. Production: Use cluster or PM2 for multi-process; set NODE_ENV=production; configure health check endpoints; apply rate limiting on public API routes

Edge Cases

If unhandled promise rejections occur: Register process.on('unhandledRejection', ...) and terminate the process; treat unhandled rejections as fatal.

If TypeScript path aliases are used: Configure tsconfig-paths or tsc-alias for runtime resolution; keep aliases consistent between tsconfig.json and bundler config.

If CPU-intensive work is needed: Offload to a worker thread via worker_threads; never block the event loop with synchronous computation.

If the database query is slow: Check for missing indexes; use EXPLAIN ANALYZE; consider read replicas for read-heavy endpoints.

If environment configuration is missing: Validate all required env vars at startup; fail fast with a clear error message listing missing keys.

If a third-party API call hangs: Set an AbortController with a timeout; never let external calls block indefinitely.

If the API must handle file uploads: Use multer (Express) or @fastify/multipart; stream to object storage; do not buffer large files in memory.

References