Express.js
Minimal Node.js web framework - build REST APIs with routing, middleware, and request/response handling in fewer than 50 lines of setup.
skill: Express.js category: Backend tags: [Express.js, Node.js, REST API, Middleware, JavaScript] readingTime: 6
Express is the default Node.js framework for REST APIs - minimal and composable. For APIs that need type safety and validation out of the box, consider Fastify (faster, TypeScript-native). For full-stack with TypeScript, consider tRPC or NestJS.
Workflow
- Set up Express with TypeScriptType-safe Express routes catch parameter mismatches and body type errors at compile time.
- Structure routes with Express RouterPutting all routes in index.ts becomes unmanageable. Router separates concerns and enables resource-based file organization.
- Validate request bodies with ZodExpress doesn't validate request data by default - parsing untrusted req.body without validation is a security risk.
- Add authentication middlewareMiddleware runs before route handlers - ideal for auth checks that apply to many routes.
- Handle errors centrallyCatching errors in every route handler creates repetition. A centralized error handler standardizes error format and logging.
Output Format
Express REST API with typed routes, Zod validation, JWT auth middleware, and central error handling.
src/
├── app.ts # Express setup, middleware
├── server.ts # Listen + graceful shutdown
├── routes/
│ ├── users.ts
│ └── posts.ts
├── middleware/
│ ├── authenticate.ts
│ └── errorHandler.ts
├── schemas/ # Zod schemas
└── services/ # DB + business logicExamples
Input
Output
Edge Cases & Gotchas
- async route handlers don't catch by default - async functions in routes that throw won't call the error middleware. Use a wrapper: const wrap = fn => (req, res, next) => fn(req, res, next).catch(next).
- Large payload DoS - Default express.json() has no size limit. Set limit: '1mb' to prevent request body attacks.
- Route order matters - Express matches routes in declaration order. Generic routes (/:id) must come after specific ones (/profile) or they shadow them.
- CORS preflight on non-GET routes - Browsers send OPTIONS preflight for POST/PUT/PATCH with custom headers. Ensure cors() middleware handles OPTIONS before other middleware.
When to Break These Rules
- Use Fastify instead of Express when throughput is the primary concern - Fastify is 2-3x faster and has schema-based validation built in.
- Use NestJS instead of Express when the team benefits from Angular-like structure (decorators, modules, DI) for large REST or GraphQL APIs.
Reference Files
https://expressjs.com/en/guide/routing.htmlhttps://expressjs.com/en/guide/error-handling.html