Node.js and Express API Architecture: A Complete Guide

Express is minimal by design — which means the architecture is entirely up to you. Here's the structure I use to keep Express APIs maintainable as they grow past a handful of routes.

By Sandaruwan Jayasundara — Senior Software Engineer | Backend Specialist

Node.js and Express remain one of the most productive stacks for building APIs — but that minimalism is a double-edged sword. Without deliberate structure, an Express app turns into a pile of routes with logic scattered across files. Here's the architecture that scales.

1. Project Structure

src/
  routes/       -> route definitions, thin, no business logic
  controllers/  -> request/response handling
  services/     -> business logic, framework-agnostic
  repositories/ -> database access
  middleware/   -> auth, validation, error handling
  config/       -> env, database, third-party clients
  utils/

The key rule: controllers stay thin, services hold logic, repositories own data access. This keeps business logic testable without spinning up an HTTP server.

2. Middleware Chain Design

3. Centralized Error Handling

app.use((err, req, res, next) => {
  const status = err.status || 500;
  res.status(status).json({
    error: { message: err.expose ? err.message : "Internal server error", code: err.code }
  });
});

Never leak stack traces or raw database errors to clients. Throw typed errors (ValidationError, NotFoundError) from services and translate them centrally.

If your controllers have try/catch blocks scattered everywhere, your error handling architecture is missing, not your try/catch discipline.

4. Validation at the Boundary

Validate every request body, query param, and route param before it reaches business logic — schema validation libraries (Zod, Joi) turn this into a declarative, type-safe step rather than manual if-checks.

5. Authentication & Security

6. Production Readiness

Bringing It Together

Express doesn't enforce architecture — that's the job of the engineer building on it. A clean layered structure, centralized error handling, and boundary validation are what separate a prototype from a production API.

I'm Sandaruwan Jayasundara — Senior Software Engineer | Backend Specialist. Explore my projects or get in touch about your backend.