backend
Why NestJS for a backend that got big
Why NestJS for a backend that got big
It's an opinionated Node framework — modules, dependency injection, decorators, Angular-style, sitting on Express by default. My platform's whole API runs on it.
Plain Express gives total freedom and zero structure. That's fine for a small API and painful past twenty-odd business domains, each needing its own services, DTOs and guards. NestJS forces a consistent shape onto every module — *.module.ts, *.controller.ts, *.service.ts — and that consistency is what keeps a large codebase navigable when there's only one person holding the whole map.
Modules are the unit of organisation. Each domain — applications/, payments/, messaging/ — imports only what it needs from core/ and exports only what other modules should use. That's what keeps one domain from reaching into another's internals.
Dependency injection — services are providers, injected by constructor:
@Injectable()
export class ApplicationsService {
constructor(private readonly db: PrismaService) {}
}
Swap PrismaService for a mock without touching the service. That's what makes the tests sane.
Guards run before a handler and decide allow or deny — auth, tenant scoping, roles all live here:
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles("admin")
@Get("applications")
Interceptors wrap request/response for cross-cutting behaviour without touching every controller. Pipes transform and validate input before it reaches a handler. Exception filters shape thrown errors into consistent HTTP responses across the whole API.
I split core/ (infrastructure many modules depend on but that isn't itself a feature — auth, the DB client, email, storage, the outbox processor, settings resolution, the realtime gateway) from modules/ (the actual business domains). It makes it obvious where a new question belongs: "how do we talk to S3" is core, "what's the application status flow" is a module.
The trade is a real learning curve and more boilerplate per feature than a minimal Express route. For something growing into dozens of modules, that upfront structure pays for itself — it's genuinely hard to make a mess in NestJS, because the framework keeps nudging you back into modules and services even under deadline pressure.