Clean Express API Design: Organize Your Code the Right Way

Table of contents

If you're learning how to build a backend using Express.js, it's important to organize your code properly. A clean project structure helps you build faster, fix bugs easily, and add new features without confusion.
What is a RESTful API?
A RESTful API is a way for different software or apps to talk to each other using the internet. For example:
- A frontend app (like a React app) makes a request to get user data and the backend (your Express API) responds by sending the user data in JSON format.
REST (Representational State Transfer) is an architectural style for building APIs using HTTP methods :
GET – to get data
POST – to create data
PUT – to update data
DELETE – to delete data
This all methods is stateless (each request is independent)
Why Project Structure Matters
As your application scales, poor structure leads to:
Duplicate logic
Hard-to-maintain code
Painful debugging
Difficulty in onboarding new developers
A good folder structure enables separation of concerns, where each component handles a specific task: routes, controllers, models, services, etc.
How to Start a Simple Express Project
1. Create a new folder and install Express
mkdir express-api
cd express-api
npm init -y
npm install express
2. Create server.js
This is the starting point of your app.
import express from 'express';
import routes from './src/routes/index.js';
import logger from './src/middlewares/logger.js';
const app = express();
const PORT = 3000;
app.use(express.json());
app.use(logger);
app.use('/api', routes);
app.listen(PORT, () => {
console.log(`🚀 Server running at http://localhost:${PORT}`);
});
Project Folder Structure
Here’s a clean way to organize your files:
express-api/
├── server.js
└── src/
├── routes/ # URL routes
├── controllers/ # Handles what to do when a route is called
├── services/ # Business logic
└── middlewares/ # Reusable functions (e.g., logging, auth)
Step-by-Step Example
Let’s create a small example for a users API.
1. Routes
Create a file: src/routes/user.routes.js
import express from 'express';
import { getAllUsers, getUserById, createUser } from '../controllers/user.controller.js';
const router = express.Router();
router.get('/', getAllUsers);
router.get('/:id', getUserById);
router.post('/', createUser);
export default router;
Now connect it in src/routes/index.js:
import express from 'express';
import userRoutes from './user.routes.js';
const router = express.Router();
router.use('/users', userRoutes);
export default router;
2. Controllers
Create a file: src/controllers/user.controller.js
import { getAll, getById, create } from '../services/user.service.js';
export const getAllUsers = (req, res) => {
const users = getAll();
res.json(users);
};
export const createUser = (req, res) => {
const newUser = create(req.body);
res.status(201).json(newUser);
};
What Are Middlewares?
Middlewares are small functions that run before your main route function.
Example: logging the request.
Create a file: src/middlewares/logger.js
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
export default logger;
Use it in server.js
:
import logger from '../src/middlewares/logger';
app.use(logger);
Why This Structure is Good
✅ Easy to read and understand
✅ Easy to manage code when your app grows
✅ Makes testing and debugging simple
✅ Helps teams work better on the same code
In Simple Words
Routes handle what URL is being called.
Controllers decide what to do with that request.
Services handle the main logic or data.
Middlewares help add features like logging or checking user permissions.
Final Tips
Keep things simple and small
Name files clearly (like
user.routes.js
,auth.controller.js
)Don't write all code in one file
Separate logic into parts (routes, controller, service)
Conclusion
When building an Express API, organizing your code properly is super important. Even if your project is small now, a clean structure will help you grow it easily in the future. Keep your logic separate, follow the REST rules, and build step-by-step.
Once you understand this structure, you’ll find backend development much easier and more fun!
Subscribe to my newsletter
Read articles from Renil Garala directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Renil Garala
Renil Garala
A 20-year-old web developer, certified in Java. Pursuing a BCA in the third year and currently learning full-stack web development from Chaicode.