Skip to content
Back to skills

Nestjs Service Pattern

ASecurity

> Encapsulate business logic in @Injectable services with repository pattern separation

  • 20 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 11, 2026
businesstypescriptrefactoringapidatabaseperformance

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 11, 2026

npx -y skills add Intense-Visions/harness-engineering --skill nestjs-service-pattern --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Nestjs Service Pattern?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Nestjs Service Pattern
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/intense-visions-nestjs-service-pattern/badge)](https://www.skillsdirectory.com/skills/intense-visions-nestjs-service-pattern)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# NestJS Service Pattern

> Encapsulate business logic in @Injectable services with repository pattern separation

## When to Use

- You are implementing business logic that should be reusable across multiple controllers
- You need to interact with a database, external API, or message queue from your application layer
- You want to separate data access concerns (repository) from business rules (service)
- You are writing unit tests and need to mock data access without touching the database

## Instructions

1. Decorate the class with `@Injectable()`. This registers it as a provider that the DI container can instantiate and inject.
2. Declare the service in the `providers` array of its module. Export it if other modules need to inject it.
3. Inject dependencies through the constructor using TypeScript types — NestJS uses reflection metadata to resolve them.
4. Keep one service per domain aggregate (e.g., `UsersService`, `OrdersService`). Avoid `AppService` catch-alls.
5. Apply the repository pattern: have the service call a repository (or Prisma/TypeORM directly) rather than embedding query logic inline.
6. Throw `HttpException` subclasses (`NotFoundException`, `ConflictException`, etc.) for domain errors so exception filters can serialize them correctly.

```typescript
@Injectable()
export class UsersService {
  constructor(private readonly prisma: PrismaService) {}

  async findOne(id: string): Promise<User> {
    const user = await this.prisma.user.findUnique({ where: { id } });
    if (!user) throw new NotFoundException(`User ${id} not found`);
    return user;
  }

  async create(dto: CreateUserDto): Promise<User> {
    const existing = await this.prisma.user.findUnique({ where: { email: dto.email } });
    if (existing) throw new ConflictException('Email already registered');
    return this.prisma.user.create({ data: dto });
  }

  async update(id: string, dto: UpdateUserDto): Promise<User> {
    await this.findOne(id); // reuse findOne for existence check
    return this.prisma.user.update({ where: { id }, data: dto });
  }

  async remove(id: string): Promise<void> {
    await this.findOne(id);
    await this.prisma.user.delete({ where: { id } });
  }
}
```

7. Use `async/await` for all async operations. Do not mix callbacks and promises.
8. Keep methods focused — a method does one thing. Extract helpers for repeated logic.

## Details

Services are the workhorses of NestJS applications. They are singleton-scoped by default (one instance shared across the entire app lifetime), which means you should not store per-request state in service instance variables.

**Scope options:** `@Injectable({ scope: Scope.REQUEST })` creates a new instance per request — useful for request-scoped data (e.g., tenant ID) but has a performance cost since the entire dependency chain must be request-scoped. Use the default `DEFAULT` (singleton) scope unless you have a concrete reason not to.

**Repository pattern with Prisma:** Rather than calling `prisma.user` everywhere in a service, some teams create a `UsersRepository` class that wraps Prisma calls and exposes domain-level methods (`findByEmail`, `findActiveUsers`). This makes the service easier to test and the data access logic easier to swap.

**Error boundaries:** Only throw HTTP exceptions in the service if it is HTTP-facing. For domain services shared between HTTP and microservice transports, throw domain-specific exceptions and convert them to `RpcException` or `HttpException` at the transport layer.

**Circular dependency between services:** When `ServiceA` depends on `ServiceB` and vice versa, inject with `forwardRef()`: `@Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB`. Prefer refactoring to a shared third service instead.

## Source

https://docs.nestjs.com/providers

## Process

1. Read the instructions and examples in this document.
2. Apply the patterns to your implementation, adapting to your specific context.
3. Verify your implementation against the details and edge cases listed above.

## Harness Integration

- **Type:** knowledge — this skill is a reference document, not a procedural workflow.
- **No tools or state** — consumed as context by other skills and agents.

## Success Criteria

- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.

Files in this skill

  • SKILL.md4.3 KB
  • skill.yaml742 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.