Node.js
Overview
Production-grade Node.js runtime and server standard. Enforces async event loop non-blocking hygiene, graceful shutdown, structured JSON logging with correlation IDs, and unhandled rejection guards.
When to Use
Activate when developing Node.js HTTP servers, Express/Fastify APIs, background workers, CLI tools, or stream-based data pipelines.
Negative Constraints (What NOT to Do)
- NEVER execute synchronous filesystem/crypto calls in request handlers (
fs.readFileSync): Always use async promises (fs.promises.*) to avoid blocking the event loop. - NEVER leave uncaught promise rejections: Every async route must use
express-async-errorsor wrap operations in try/catch callingnext(err). - NEVER buffer large files/payloads entirely in memory (
fs.readFile): Always use Streams or Pipelines (stream.pipeline) for processing large files. - NEVER store in-memory session or user state on a single process instance: Use Redis or an external state store to allow multi-instance scaling.
- NEVER ignore
SIGTERM/SIGINTshutdown signals: Always implement graceful shutdown to close open DB pools and drain active HTTP connections.
Rules & Patterns
Architecture
- Layered architecture: Routes → Controllers → Services → Repositories
- Dependency injection — don't import dependencies directly in services
- Config from environment — never hardcode secrets, use env variables
- Graceful shutdown — handle SIGTERM, close connections, drain requests
Error Handling
- Never swallow errors — always handle or re-throw
- Custom error classes — extend Error with HTTP status codes
- Global error handler — catch unhandled rejections and uncaught exceptions
- Structured logging — JSON logs with request ID, timestamp, level
class AppError extends Error {
constructor(
public message: string,
public statusCode: number = 500,
public code: string = 'INTERNAL_ERROR'
) {
super(message);
this.name = 'AppError';
}
}
API Design
- RESTful conventions — GET (read), POST (create), PUT (full update), PATCH (partial), DELETE
- Consistent response format —
{ data, error, pagination } - Validation at the edge — validate request body/params with Zod or Joi
- Rate limiting — protect against abuse
- CORS — configure explicitly, never use
*in production
Security
- Helmet.js — security headers
- Input validation — never trust client input
- SQL injection — always use parameterized queries
- XSS — sanitize output, use Content-Security-Policy
- Authentication — JWT with short expiry + refresh tokens
- Secrets — environment variables, never in code
Database
- Connection pooling — don't create connections per request
- Migrations — version-controlled schema changes
- Transactions — for multi-step operations
- Indexes — add indexes for frequently queried columns
Performance
- Async/await — never block the event loop
- Streaming — for large files and data sets
- Caching — Redis for frequently accessed data
- Clustering — use PM2 or cluster module for multi-core
Testing
- Unit tests — services and utilities
- Integration tests — API endpoints with test database
- Test isolation — each test should be independent
- Fixtures — use factories, not shared state
File Structure
src/
├── config/ # Configuration
├── modules/ # Feature modules
│ └── users/
│ ├── users.controller.ts
│ ├── users.service.ts
│ ├── users.repository.ts
│ ├── users.routes.ts
│ ├── users.types.ts
│ └── users.test.ts
├── shared/ # Shared utilities
│ ├── middleware/
│ ├── errors/
│ └── utils/
├── types/ # Global types
└── app.ts # App entry point
Code Examples
See EXAMPLES.md for detailed code examples.
Validation Checklist
What to verify during the review phase before completing the task.
Common Mistakes
Anti-patterns and things to explicitly avoid. See TROUBLESHOOTING.md.
Integration Notes
How this skill interacts with other skills.