DEV Community

Tanmay Gupta
Tanmay Gupta

Posted on

Express.js Folder Structure Explained

When you're just starting out with Express.js, it's easy to write everything in a single file like index.js. But as your application grows, this quickly becomes hard to manage.

That’s why a clean and scalable folder structure is crucial.

In this blog post, you’ll learn:

  • Why folder structure matters
  • A standard way to organize an Express app
  • What each folder/file does

Why Organize?

A good project structure:

  • Makes your code readable
  • Keeps logic separated
  • Helps you scale easily
  • Makes debugging and testing simpler

Basic Express Folder Structure

Here’s a recommended folder structure for a moderate-sized Express app:

my-express-app/
├── node_modules/
├── src/
│   ├── controllers/
│   ├── routes/
│   ├── models/
│   ├── middleware/
│   ├── config/
│   ├── utils/
│   └── app.js
├── .env
├── package.json
└── server.js
Enter fullscreen mode Exit fullscreen mode

src/ — Main App Folder

This folder holds all your actual source code. Inside it:


controllers/

This folder contains your business logic. Each file typically handles a specific route or resource.

// src/controllers/userController.js
exports.getUsers = (req, res) => {
  res.send('List of users');
};
Enter fullscreen mode Exit fullscreen mode

routes/

This is where you define Express routes and connect them to controllers.

// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.get('/users', userController.getUsers);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

models/

Used for database models. You might use Mongoose for MongoDB or Sequelize for SQL.

// src/models/User.js
const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  name: String,
  email: String,
});

module.exports = mongoose.model('User', UserSchema);
Enter fullscreen mode Exit fullscreen mode

middleware/

Custom middleware functions like authentication, logging, error handling, etc.

// src/middleware/logger.js
const logger = (req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  next();
};

module.exports = logger;
Enter fullscreen mode Exit fullscreen mode

config/

Store configuration files like DB connection, environment setup, constants.

// src/config/db.js
const mongoose = require('mongoose');

const connectDB = async () => {
  await mongoose.connect(process.env.MONGO_URI);
  console.log('MongoDB connected');
};

module.exports = connectDB;
Enter fullscreen mode Exit fullscreen mode

utils/

Helper functions and utilities (e.g., validators, formatters, token generators).

// src/utils/generateToken.js
const jwt = require('jsonwebtoken');

const generateToken = (id) => {
  return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '1d' });
};

module.exports = generateToken;
Enter fullscreen mode Exit fullscreen mode

app.js

This is where you configure Express and mount all routes & middleware.

const express = require('express');
const userRoutes = require('./routes/userRoutes');
const logger = require('./middleware/logger');

const app = express();

app.use(express.json());
app.use(logger);
app.use('/api', userRoutes);

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

server.js

Entry point of the app. Responsible for starting the server.

const app = require('./src/app');
const dotenv = require('dotenv');
dotenv.config();

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

.env

Environment variables like:

PORT=5000
MONGO_URI=mongodb+srv://...
JWT_SECRET=mysecretkey
Enter fullscreen mode Exit fullscreen mode

Use the dotenv package to access these in your app.


Benefits of This Structure

  • Clear separation of concerns
  • Easier testing and debugging
  • Scales well with team collaboration
  • Ready for features like logging, authentication, APIs, etc.

Next Steps

Now that you have a solid structure, you can:

  • Add authentication
  • Connect a database
  • Deploy to Render, Vercel, or Heroku
  • Use Postman to test your APIs

TL;DR

Keep your code clean by:

  • Separating files by purpose
  • Moving configs and middleware to their own places
  • Treating your src folder as the app’s core

💡 Pro tip: You don’t need to use this full structure on day one. Start simple and refactor as your app grows.

Happy coding 👨‍💻👩‍💻

Top comments (0)