DEV Community

Himanshu Gupta
Himanshu Gupta

Posted on

πŸ—‚οΈ Scalable Folder Structure for Node.js + Express.js Projects (2025 Edition)

πŸ“¦ Why Project Structure Matters
As your Node.js app grows, a good folder structure keeps your sanity intact. It makes your app:

Easier to scale

Easier to test

Easier to onboard new devs

Forget monolithic files. Let’s modularize smartly.

πŸ“ Recommended Structure

my-app/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ config/ # App configuration (env, DB, etc.)
β”‚ β”œβ”€β”€ modules/ # Feature-based modules (User, Auth, etc.)
β”‚ β”‚ └── user/
β”‚ β”‚ β”œβ”€β”€ user.controller.ts
β”‚ β”‚ β”œβ”€β”€ user.service.ts
β”‚ β”‚ β”œβ”€β”€ user.model.ts
β”‚ β”‚ β”œβ”€β”€ user.routes.ts
β”‚ β”‚ └── user.validators.ts
β”‚ β”œβ”€β”€ middleware/ # Custom middlewares
β”‚ β”œβ”€β”€ utils/ # Utility functions/helpers
β”‚ β”œβ”€β”€ jobs/ # Cron jobs, background workers
β”‚ β”œβ”€β”€ app.ts # Express app setup
β”‚ └── server.ts # Entry point
β”œβ”€β”€ tests/ # Unit and integration tests
β”œβ”€β”€ .env
β”œβ”€β”€ .env.example
β”œβ”€β”€ tsconfig.json # TypeScript config (if using TS)
β”œβ”€β”€ package.json
└── README.md
πŸ” Breakdown
src/modules/ β€” πŸ’‘ Feature First
Split features into self-contained modules:

Easier to test and scale

Encourages separation of concerns

Think DDD-lite (Domain Driven Design)

For example:

modules/
└── auth/
β”œβ”€β”€ auth.controller.ts
β”œβ”€β”€ auth.service.ts
β”œβ”€β”€ auth.routes.ts
β”œβ”€β”€ auth.model.ts
└── auth.validators.ts
src/config/ β€” πŸ”§ Config Central
Centralized configuration logic:

ts

// config/database.ts
import mongoose from 'mongoose';
export const connectDB = async () => {
await mongoose.connect(process.env.MONGO_URI!);
};
src/middleware/ β€” πŸ”’ Middlewares
Store custom Express middleware here:

Error handlers

Auth guards

Rate limiters

Logging middleware (e.g., Morgan)

src/utils/ β€” 🧰 Shared Helpers
For things like:

Response formatters

Token generation

Password hashing

πŸ§ͺ tests/ β€” Testing-First
Organize unit and integration tests per module:

pgsql

tests/
└── user/
β”œβ”€β”€ user.controller.test.ts
└── user.service.test.ts
Use tools like:

Jest or Vitest (unit tests)

Supertest (API tests)

βœ… Bonus Tips
Add src/types/ if you need global types.

Use a .env.example for teammates to know required environment variables.

Lint + Format using eslint and prettier.

Use module-alias to avoid ugly ../../ imports.

Use a layered structure only when needed β€” don’t over-engineer a todo app.

πŸš€ TL;DR
Use this structure if:
βœ… You're building a mid-to-large scale API
βœ… You want clean, modular code
βœ… You care about testing and future scaling

πŸ’¬ What’s Your Take?
Got a favorite structure? Drop it in the comments!
Let’s build better backends, one folder at a time. πŸ§‘β€πŸ’»πŸ”₯

Top comments (0)