Designing a Scalable Folder Structure for Our Node.js E-commerce API (Clean Architecture + Feature-Based)
Hey folks! ๐
In the last post, we saw how messy traditional code gets when everything (HTTP, business rules, DB) is thrown together. We fixed that with Clean Architecture layers.
But layers alone aren't enough when your app grows to 20+ features. Scrolling through giant controllers/ or services/ folders becomes a nightmare.
The fix? Organize by feature (also called vertical slices or feature-first), while keeping Clean Architecture inside each feature.
Goal Recap
- Related code stays close together
- Easy to navigate and add new features
- Scales beautifully as the e-commerce app grows
Step 1: Identify the Core Business Features
E-commerce revolves around clear business capabilities:
- Users (registration, profiles, addresses)
- Products (catalog, details, search)
- Cart (add/remove items, totals)
- Orders (create, track, cancel)
- Payments (integrate gateways like Stripe/Razorpay)
- Reviews & Authentication (login, JWT, roles)
We group code by these features instead of by type.
src/
โโโ features/
โโโ users/
โโโ products/
โโโ cart/
โโโ orders/
โโโ payments/
โโโ reviews/
Want to work on "products"? Just open src/features/products โ everything is right there. No more hunting across folders!
Step 2: Apply Clean Architecture Inside Each Feature
Inside a feature folder, we still separate concerns using Clean layers:
src/
โโโ features/
โโโ users/
โโโ domain/ โ Core business concepts (pure JS/TS, no frameworks!)
โโโ application/ โ Use cases / business flows
โโโ infrastructure/ โ DB, external services (Mongo, email, etc.)
โโโ presentation/ โ API controllers, routes, validation
Domain Layer โ The Heart โค๏ธ
Pure business rules. No Express, no MongoDB imports.
Contains:
- Entities (e.g., User with methods like
changeEmail()) - Value Objects (e.g., Email, Password)
- Repository interfaces (abstract, e.g.,
IUserRepository)
domain/
โโโ entities/
โ โโโ User.js
โโโ repositories/
โโโ IUserRepository.js // โ just the contract!
Rule: This layer never depends on outer layers or tech. It stays stable forever.
Application Layer โ The Brain ๐ง
Use cases โ what the system can actually do.
Examples: RegisterUser, LoginUser, UpdateProfile, AddAddress
application/
โโโ use-cases/
โโโ registerUser.js
โโโ loginUser.js
โโโ updateProfile.js
These coordinate domain entities + call repositories (via interfaces).
Infrastructure Layer โ The Tools ๐ง
Concrete implementations of domain interfaces.
infrastructure/
โโโ repositories/
โ โโโ MongoUserRepository.js // implements IUserRepository
โโโ services/
โโโ JwtService.js
Switch DB from Mongo โ PostgreSQL? Only change files here. Domain & application stay untouched!
Presentation Layer โ The Doorway ๐ช
Handles HTTP (Express routes/controllers).
presentation/
โโโ controllers/
โ โโโ userController.js
โโโ routes/
โ โโโ userRoutes.js
โโโ dtos/ (optional: request/response shapes)
โโโ registerUser.dto.js
It calls application use cases and returns responses.
Full Example: Users Feature Folder
src/
โโโ features/
โโโ users/
โโโ domain/
โ โโโ entities/
โ โ โโโ User.js
โ โโโ repositories/
โ โโโ IUserRepository.js
โโโ application/
โ โโโ use-cases/
โ โโโ registerUser.js
โ โโโ loginUser.js
โ โโโ updateProfile.js
โโโ infrastructure/
โ โโโ repositories/
โ โ โโโ MongoUserRepository.js
โ โโโ services/
โ โโโ JwtService.js
โโโ presentation/
โโโ controllers/
โ โโโ userController.js
โโโ routes/
โ โโโ userRoutes.js
โโโ dtos/
โโโ registerUser.dto.js
Repeat this pattern for products/, orders/, etc.
Classic Clean Architecture (onion) โ dependencies point inward
Vertical slices (feature-based) vs traditional horizontal layers โ features group everything vertically
Why This Combo Rocks for E-commerce
- High cohesion โ All "user" code in one place โ faster development
- Low coupling โ Features don't touch each other unless needed
- Scalability โ Add "subscriptions" or "wishlist" as new feature folders
- Maintainability โ New devs onboard quickly ("show me the orders feature")
- Testability โ Mock infrastructure โ unit test domain & application easily
- Tech independence โ Swap DB, framework, or add GraphQL? Minimal pain
This is a pragmatic blend of Clean Architecture (for inner stability) + Vertical Slice (for outer organization). Many production Node.js e-commerce APIs use exactly this.
- Setting up the project