π¦ 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)