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.