Skip to content

03 Folder Structure

DodaTech 4 min read

title: Folder Structure for Node.js REST API Projects weight: 13 date: 2026-06-28 lastmod: 2026-06-28 description: Learn the recommended folder structure for Node.js REST API projects with separation of routes, controllers, models, middleware, and configuration layers. tags: [api-development, nodejs]


A well-organized Node.js REST API project separates concerns into distinct folders for routes, controllers, models, middleware, services, configuration, and utilities, making the codebase maintainable and scalable.

```mermaid
flowchart TD
  A[Project Root] --> B[src/]
  B --> C[routes/]
  B --> D[controllers/]
  B --> E[models/]
  B --> F[middleware/]
  B --> G[services/]
  B --> H[config/]
  B --> I[utils/]
  C --> J[userRoutes.js]
  C --> K[orderRoutes.js]
  D --> L[userController.js]
  E --> M[User.js]
  style A fill:#e1f5fe
  style B fill:#c8e6c9

The standard structure is: routes define endpoints and wire them to controllers. Controllers handle request/response logic and call services. Services contain business logic. Models represent database schemas. Middleware handles cross-cutting concerns like auth and logging. Config stores environment-specific settings.

Think of this structure like a restaurant kitchen. Routes are the menu (what dishes are available). Controllers are the waiters (take orders and serve food). Services are the chefs (prepare the food). Models are the recipe books (ingredient definitions).

Example: Folder Structure

project/
├── src/
│   ├── config/
│   │   ├── database.js
│   │   └── environment.js
│   ├── controllers/
│   │   ├── userController.js
│   │   └── orderController.js
│   ├── middleware/
│   │   ├── auth.js
│   │   ├── errorHandler.js
│   │   └── validate.js
│   ├── models/
│   │   ├── User.js
│   │   └── Order.js
│   ├── routes/
│   │   ├── index.js
│   │   ├── userRoutes.js
│   │   └── orderRoutes.js
│   ├── services/
│   │   ├── userService.js
│   │   └── orderService.js
│   ├── utils/
│   │   ├── logger.js
│   │   └── helpers.js
│   └── app.js
├── tests/
│   ├── unit/
│   └── integration/
├── .env
├── .gitignore
└── package.json

Example: Route Wiring

// src/routes/index.js
const express = require('express');
const router = express.Router();

const userRoutes = require('./userRoutes');
const orderRoutes = require('./orderRoutes');

router.use('/api/users', userRoutes);
router.use('/api/orders', orderRoutes);

module.exports = router;

// src/app.js
const routes = require('./routes');
app.use(routes);

Example: Controller Layer

// src/controllers/userController.js
const userService = require('../services/userService');

exports.getUser = async (req, res, next) => {
  try {
    const user = await userService.findById(req.params.id);
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    res.json(user);
  } catch (error) {
    next(error);
  }
};

exports.createUser = async (req, res, next) => {
  try {
    const user = await userService.create(req.body);
    res.status(201).json(user);
  } catch (error) {
    next(error);
  }
};

Common Mistakes

  1. Putting all logic in route handlers — Route files with hundreds of lines of business logic are hard to test and maintain. Delegate to controllers and services.
  2. Mixing concerns in a single file — A file should have one responsibility. Database queries, validation, and business logic each belong in separate layers.
  3. Circular dependencies — Controllers importing services that import the same controllers causes crashes. Keep the dependency chain linear.
  4. Ignoring a services layer — Putting business logic in controllers makes them untestable without HTTP mocking. Services are pure functions that are easy to test.
  5. Flat file structure — All files in src/ without subdirectories becomes unmanageable beyond 10-15 files. Create subdirectories by concern.

Practice Questions

  1. What is the purpose of the services layer in this architecture?
  2. Why should routes be separate from controllers?
  3. How do you handle environment-specific configuration?
  4. What is the benefit of a models layer?
  5. Challenge: Set up the folder structure for a blog API with posts, comments, and authors. Create stub files for routes, controllers, services, and models. Wire them together in the main app.

FAQ

Should I use a routes file for each resource?

Yes, creating separate route files for each resource keeps the code organized and makes it easy to find endpoint definitions.

What is the difference between controllers and services?

Controllers handle HTTP concerns (request, response, status codes). Services contain business logic and are framework-agnostic, making them testable without HTTP.

How many files should be in a single directory?

Aim for 5-10 files per directory. When a directory grows beyond that, consider splitting into subdirectories or modules.

Should models be database-specific or agnostic?

Models should abstract the database so you can change databases without changing business logic. Use an ORM like Mongoose (MongoDB) or Prisma (SQL).

Where should validation logic live?

Validation can live in middleware (for request validation) or in services (for business rule validation). Schema validation is typically middleware.

Mini Project

Create a complete folder structure for an e-commerce API with products, categories, cart, orders, and users. Implement stubs for each layer (routes, controllers, services, models). Wire everything together and verify the server starts without errors.

What's Next

Now learn about routing in the next lesson on Building REST APIs with Node.js.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro