Facebook Pixel

Express API Structure Roadmap: From Spaghetti to Modular

A roadmap for structuring an Express API, from spaghetti to modular.

Express API Structure Roadmap: From Spaghetti to Modular

A roadmap for structuring an Express API, from spaghetti to modular. Each step is small and shippable.

Step 1: Start With app.js and a Few Routes

For a tiny app, put routes in app.js. app.get('/users', ...), app.post('/users', ...). Fine for prototypes.

Step 2: Add a Folder for Routes

When you have more than ~10 routes, move them into a routes/ folder. Each feature gets a file: routes/auth.js, routes/users.js.

Step 3: Mount Routers in app.js

app.use('/auth', require('./routes/auth'));
app.use('/users', require('./routes/users'));

app.js becomes thin: global middlewares, router mounts, error handler.

Step 4: Add Controllers

Move logic out of routes into controllers/. Routes only declare endpoints and bind to controllers.

Step 5: Add a Services Layer

When controllers get long, move logic into services/. Controllers parse, call, respond. Services do the work.

Step 6: Add Middlewares

Create a middlewares/ folder. auth.js, validate.js, error.js. Apply per route or per router.

Step 7: Add Validations

Create a validations/ folder with Zod schemas. Apply with a validate(schema) middleware per route.

Step 8: Add a Models Folder

Each Mongoose model in its own file: models/user.js, models/post.js.

Step 9: Add a Utils Folder

Shared helpers: ApiError, asyncHandler, logger, db connection.

Step 10: Add a Config Folder

Centralize env var loading and app-level config. No other file reads process.env directly.

Step 11: Version the API

Mount routers under /api/v1. When you make breaking changes, add v2. Old clients keep using v1.

Step 12: Move to the Module Pattern (For Large Apps)

Group each feature into a module: src/modules/users/ with router, controller, service, model, validations. Mount modules in app.js. Use for medium to large apps.

The Takeaway

The Express API structure roadmap: start with app.js, add a routes folder, mount routers, add controllers, add services, add middlewares, add validations, add models and utils folders, add a config folder, version the API, and move to the module pattern for large apps. Each step is small and shippable.

Start with app.js, add a routes folder, mount routers in app.js, add controllers, add a services layer, add middlewares, add validations, add models and utils folders, add a config folder, version the API, and move to the module pattern for large apps.

When you have more than ~10 routes. Move them into a routes/ folder with one file per feature. Mount each router in app.js with app.use('/path', router). app.js becomes thin.

When controllers get long. Move logic into services/. Controllers parse the request, call a service, send the response. Services do the work and are reusable and testable without an HTTP context.

For medium to large apps. Group each feature into a module (src/modules/users/ with router, controller, service, model, validations). Mount modules in app.js. For tiny apps, a flat structure is fine.

Mount routers under /api/v1, /api/v2, etc. app.use('/api/v1/users', require('./routes/v1/users')). Bump the version on breaking changes; non-breaking changes (adding fields) do not need a new version.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.