Software Development

Node.js REST API Best Practices: Security, Performance, and Structure 2025

10 min read PCCVDI Editorial Team

Node.js remains the most popular choice for REST API development in 2025. But a badly structured Node.js API is a source of security vulnerabilities, performance bottlenecks and maintenance nightmares. These are the practices we enforce on every production API.

1 Project Structure

Use a layered architecture: routes (HTTP handling), controllers (request/response), services (business logic) and repositories (data access). Never put business logic in route handlers. Keep each layer unit-testable in isolation. Use absolute imports with path mapping rather than relative chains. Separate your app.js (Express setup) from server.js (HTTP listener) to enable clean testing.

2 Input Validation and Security

Validate all input at the boundary using Zod or Joi. Never trust client-supplied data — validate types, lengths, formats and business rules before they reach your services. Use helmet.js for secure HTTP headers. Implement rate limiting (express-rate-limit) on all public endpoints, especially auth endpoints. Parameterise all database queries — never string-interpolate user input into SQL or MongoDB queries.

3 Authentication and Authorisation

Use short-lived JWT access tokens (15 minutes) with refresh token rotation. Store refresh tokens in HttpOnly cookies, not localStorage. Implement RBAC at the service layer, not the route layer, so business rules are enforced even when called from internal services. Use bcrypt with a cost factor of 12+ for password hashing. Never log passwords, tokens or PII.

4 Error Handling

Create a custom AppError class extending Error with statusCode and isOperational properties. Centralise error handling in a single Express error middleware. Operational errors (validation failures, not found, unauthorised) get structured JSON responses. Programming errors (unhandled exceptions) should trigger a process restart via PM2 or your process manager. Use a correlation ID (X-Request-ID) to trace errors across services.

5 Performance

Never block the event loop with synchronous CPU work — use worker_threads for computation. Cache aggressively: Redis for session data and frequently-read resources. Use database connection pools (pg-pool, Mongoose connection pool) — never create a new connection per request. Enable gzip compression via the compression middleware. For high-throughput APIs, consider Fastify over Express — it is 2-3x faster on the same Node.js version.

P
PCCVDI Editorial Team
Our articles are written and reviewed by practising engineers delivering enterprise IT solutions from New Delhi.
Free Consultation

Transform Your IT Infrastructure Today

A complimentary 30-minute strategy call with certified engineers — no sales pitch, just straightforward technical guidance.

No credit card required Response within 24 hours Speak directly with engineers