Clean Architecture in MERN
The MERN stack makes it easy to put MongoDB queries directly in Express route handlers. That works until the codebase hits 50 modules and every change breaks three unrelated features.
Layer Responsibilities
| Layer | MERN Mapping | |-------|-------------| | Domain | Entities, value objects, repository interfaces | | Application | Use cases orchestrating domain + repositories | | Infrastructure | Mongoose models, Redis clients, external APIs | | Presentation | Express routes, React components, GraphQL resolvers |
Dependencies point inward. Domain knows nothing about Express or React.
DDD-Lite Without Ceremony
You don't need full bounded context workshops. Start with:
- Entities with identity and invariants (e.g., LeaveRequest cannot exceed balance)
- Use cases as single-responsibility functions (SubmitLeaveRequest, ApproveLeaveRequest)
- Repository interfaces in domain, Mongoose implementations in infrastructure
Testing Becomes Practical
Use cases with injected repositories are unit-testable without spinning up MongoDB:
const result = await submitLeaveRequest({
employeeId: 'emp-1',
dates: { start: '2026-03-01', end: '2026-03-03' },
leaveRepository: mockLeaveRepo,
workflowEngine: mockWorkflow,
});
React Side
Mirror the separation:
- Hooks/containers call API clients
- Components receive props, no fetch logic
- API clients map DTOs to view models
When to Bend the Rules
Prototypes and one-off scripts can skip layers. Production feature modules should not.
Clean Architecture in MERN isn't academic — it's how you keep a modular monolith maintainable at scale.