Skip to main content

What are Singleton providers?

What a Singleton provider is

A Singleton provider is a provider with only one instance for the whole NestJS application. The first time NestJS's container creates that provider, it caches the instance, and every later request for that provider gets the same copy.

Example

javascript
import { Injectable } from '@nestjs/common'; @Injectable() export class CounterService { private counter = 0; increment() { this.counter++; return this.counter; } }

And two controllers use this service:

javascript
import { Controller, Get } from '@nestjs/common'; import { CounterService } from './counter.service'; @Controller('a') export class AController { constructor(private readonly counterService: CounterService) {} @Get() add() { return this.counterService.increment(); } } @Controller('b') export class BController { constructor(private readonly counterService: CounterService) {} @Get() add() { return this.counterService.increment(); } }

What happens:

  • NestJS creates one shared instance of CounterService;
  • both controllers (AController and BController) use the same object;
  • the counter's value is shared:
RequestResult
GET /a1created for the first time
GET /b2uses the same instance

Why this is convenient

  • Saves resources, the object is created only once.
  • Shared state, handy for caching data, holding a connection pool, etc.
  • Simplicity, no need to manually manage the object's lifetime.

How NestJS decides a provider is a Singleton

By default, every provider in NestJS has scope: DEFAULT, and DEFAULT means singleton.

javascript
@Injectable({ scope: Scope.DEFAULT }) // the same as just @Injectable() export class MyService {}

Other kinds of scope

ScopeDescription
Singleton (DEFAULT)One instance for the whole application (the default)
RequestA new instance for every HTTP request
TransientA new instance for every injection (a fresh object every time)

A Request-Scoped provider example:

javascript
import { Injectable, Scope } from '@nestjs/common'; @Injectable({ scope: Scope.REQUEST }) export class RequestService { constructor() { console.log('A new instance for this request!'); } }

In this case, Nest creates a new object for every HTTP request, instead of reusing a shared one.

When a Singleton provider is a good idea

It's a great fit for:

  • services with shared logic that doesn't depend on the request;
  • logging, configuration, DB access (a single connection);
  • caching, tokens, services that don't hold unique per-request data.

When a Singleton provider is a bad idea

Don't use a Singleton if:

  • the provider holds state tied to a specific request;
  • it needs to be isolated between users;
  • it holds user data that can't be shared across requests.

In those cases, Scope.REQUEST or Scope.TRANSIENT is the right choice.

Summary

ConceptDescription
Singleton providerOne shared provider instance for the whole application
CreatedOnce, when the module initializes
UsedEverywhere it's injected
By defaultEvery NestJS provider is a singleton
AdvantagesFaster, cheaper, convenient for caches, constants, the DB
LimitationsNot suited for dependencies that are unique per request

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.