Express.js Cursor Rules: Node.js Backend Guide
Cursor rules for Express.js covering middleware patterns, routing, error handling, validation, and testing for maintainable Node.js APIs.

Overview
Express.js is the standard Node.js web framework, powering millions of APIs with its minimalist middleware architecture. These cursor rules enforce modular routing, async error handling, security best practices, and structured validation to help AI assistants generate clean, production-ready Node.js code. Whether you're building REST APIs, GraphQL servers, or full-stack backends, these rules ensure your project follows Express conventions and Node.js best practices.
Note:
Enforces middleware composition patterns, express.Router modularity, async error boundaries, security headers, input validation, and testing conventions.
Rules Configuration
---
description: Enforces production-grade Express.js patterns including middleware chains, modular routing, async error handling, security, and validation. Provides guidelines for clean, testable Node.js APIs.
globs: **/*.js,**/*.ts
---
# Express.js Best Practices
You are an expert in Express.js, Node.js backend development, and modern JavaScript/TypeScript patterns.
You understand middleware composition, REST API design, security hardening, and production deployment concerns.
### Project Structure
- /routes — modular route files organized by resource domain
- /middleware — custom middleware functions (auth, validation, logging)
- /controllers — request handlers separated from route definitions
- /services — business logic layer kept independent of HTTP concerns
- /utils — shared utilities and helper functions
- /tests — Jest/Supertest test files mirroring the source structure
### Middleware & Request Pipeline
- Apply global middleware in app.js/server.js before route definitions
- Use express.json() and express.urlencoded() for body parsing
- Chain middleware on specific routes: .get(path, auth, validate, handler)
- Never swallow errors in middleware — always call next(err) or throw
- Use express.Router() to namespace routes under /api/v1/users etc.
- Move reusable logic (auth, rate-limit, logging) into middleware functions
### Error Handling
- Create a centralized error-handling middleware with (err, req, res, next) signature
- Wrap async route handlers with express-async-errors or a custom catchAsync wrapper
- Define custom error classes (AppError, ValidationError, AuthError) extending Error
- Return structured JSON: { error: { message, code, details? } }
- Log errors with a dedicated logger; never expose stack traces in production
### Security
- Use helmet() for security headers (CSP, HSTS, XSS protection)
- Enable CORS with explicit origin whitelist via the cors package
- Rate-limit auth and mutation endpoints with express-rate-limit
- Validate all input (params, query, body) with express-validator or Joi
- Hash passwords with bcrypt; store secrets in environment variables
- Sanitize user input against NoSQL injection and XSS
### Validation & Input
- Define validation schemas per route in a /validators directory
- Return 422 with field-level error messages on validation failure
- Use express-validator's .isEmail(), .isLength(), .matches() for common checks
- Validate MongoDB ObjectIDs with .isMongoId() on route params
- Strip unknown fields from request bodies to prevent mass assignment
### Testing & Quality
- Write integration tests with Jest and Supertest
- Test each endpoint for success, validation errors, auth failures, and edge cases
- Use factory functions for test data generation
- Mock external services (databases, APIs) in unit tests
- Run ESLint with Airbnb or Standard config; format with Prettier
- Set NODE_ENV=test for testing, NODE_ENV=production for deployment
### API Design
- Use RESTful resource naming: GET /users, POST /users, GET /users/:id
- Return consistent response envelopes: { data, meta?, error? }
- Use HTTP status codes correctly (200, 201, 204, 400, 401, 403, 404, 422, 500)
- Implement pagination with page/limit query params and X-Total-Count header
- Version APIs via URL prefix: /api/v1/ — avoid header-based versioning
Installation
Create express.mdc in your project's .cursor/rules/ directory and paste the configuration above. Cursor and Windsurf both read .cursor/rules/ — Copilot users place it in .github/copilot-instructions.md instead.
Examples
// routes/users.js — Modular router with validation, auth, and controller
const { Router } = require('express');
const { body, param } = require('express-validator');
const { authenticate } = require('../middleware/auth');
const { validate } = require('../middleware/validate');
const usersController = require('../controllers/users');
const router = Router();
router.get('/',
authenticate,
usersController.list
);
router.post('/',
authenticate,
[
body('email').isEmail().normalizeEmail(),
body('name').trim().isLength({ min: 2, max: 100 }),
body('password').isLength({ min: 8 }),
validate,
],
usersController.create
);
router.get('/:id',
authenticate,
param('id').isMongoId(),
validate,
usersController.show
);
module.exports = router;
// middleware/errorHandler.js — Centralized async error handler
class AppError extends Error {
constructor(message, statusCode, code) {
super(message);
this.statusCode = statusCode;
this.code = code;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
const catchAsync = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
const errorHandler = (err, req, res, next) => {
const statusCode = err.statusCode || 500;
const message = err.isOperational ? err.message : 'Internal Server Error';
console.error(`[${err.code || 'ERROR'}] ${err.message}`);
res.status(statusCode).json({
error: {
message,
code: err.code || 'INTERNAL_ERROR',
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
},
});
};
module.exports = { AppError, catchAsync, errorHandler };
Related Resources
Related Articles
Vue Cursor Rules: Composition API and SFC Best Practices
Vue cursor rules for Composition API, single-file components, template syntax, reactivity, testing, and performance to produce clean, maintainable applications
Django Cursor Rules: Python Web Framework Guide
Cursor rules for Django development covering models, views, serializers, ORM optimization, REST APIs, and Django REST Framework for production web applications.
Dart Cursor Rules: Cross-Platform Development Guide
Cursor rules for Dart development covering null safety, async programming, streams, isolates, and package management for Flutter and server-side applications.