Service layer pattern
Business logic and orchestration: how we keep controllers thin and centralize domain behavior.
Overview
The service layer holds business logic and coordinates data access. Controllers (see stack controller-layer) delegate to services; services inject and use the repository-layer for persistence and use shared types/serialization for responses.
Backend
- Technology: NestJS injectable services (see stack rule
framework). Services are registered in modules and injected where needed. - Responsibilities: Validate and orchestrate use cases; call the repository layer for data; transform results (e.g. with
plainToInstancefrom shared DTOs) before returning to controllers. Configuration (e.g. AppConfigService) is injected in services when needed at runtime. - Integration: Uses
repository-layer(Prisma Client) for data access. Uses patternserialization(class-transformer) to map ORM results to shared DTOs. Other modules (e.g. mailing) inject their services into the service layer for cross-cutting behavior (e.g. sending email).
Implementation
The boilerplate uses standard NestJS providers: each feature module exposes one or more services that controllers inject. Services inject PrismaService (or the repository abstraction) and optionally AppConfigService, MailingService, etc. They return domain data or DTOs; the response interceptor (see pattern responses) wraps success responses. No separate “application service” vs “domain service” split unless a project introduces it.
References
- Stack:
framework(NestJS),controller-layer(caller),configuration(AppConfigService in services). - Pattern:
repository-layer(data access),serialization(transforming results).