Providers are the core concept behind NestJS's dependency injection system. This lesson explains what a provider is, how @Injectable() marks a class as one, and how providers get created and shared.
What Is a Provider?
A provider is simply a class that can be injected as a dependency, most commonly a service, but also repositories, factories, or helper classes. Providers are marked with the @Injectable() decorator and registered in a module's providers array.
Nest's dependency injection container instantiates providers, resolves their own dependencies recursively, and hands the finished instance to whatever class asks for it in its constructor.
@Injectable() is what tells Nest's container this class participates in dependency injection, without it, Nest cannot construct or inject the class automatically.
Registering and Injecting a Provider
@Module({
providers: [CatsService],
})
export class CatsModule {}
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
}
A provider must appear in a module's providers array to be constructible by that module.
Injection happens through the constructor, Nest matches the parameter's type to a registered provider.
private readonly in a constructor parameter is shorthand for declaring and assigning a class property.
Providers are singletons by default, one instance is shared across all classes that inject them.
Providers Cheatsheet
The essentials for defining and registering providers.
Concept
Example
Notes
Mark as injectable
@Injectable()
Required for Nest to manage the class
Register
providers: [CatsService]
Makes it constructible within the module
Inject
constructor(private svc: CatsService)
Type-based injection via constructor
Share with other modules
exports: [CatsService]
Allows importing modules to inject it
Custom token
{ provide: 'TOKEN', useValue: x }
Injects a value instead of a class instance
Provider Scope
By default, every provider is a singleton scoped to the entire application, the same instance is reused for every request. Nest also supports REQUEST scope (a new instance per incoming request) and TRANSIENT scope (a new instance every time it's injected), configured via the @Injectable({ scope }) option.
Scope
Behavior
DEFAULT
One shared instance for the whole application (fastest, most common)
REQUEST
A new instance created per incoming request
TRANSIENT
A new instance created every time it is injected
Providers Are Not Just Services
Anything Nest's DI container can construct and inject counts as a provider, custom repositories, factory functions, configuration objects, even plain values, not only classes named *Service.
Repositories wrapping database access are providers.
Guards, pipes, and interceptors can themselves be injectable providers.
Custom providers can supply a static value or the result of a factory function.
Common Mistakes
Forgetting @Injectable() on a class that's meant to be a provider.
Registering a provider in one module but trying to inject it into an unrelated module without exporting/importing it.
Assuming every provider is stateless just because it's a singleton, shared mutable state can leak across requests.
Overusing REQUEST scope where it isn't needed, it disables some performance optimizations Nest applies to singletons.
Key Takeaways
A provider is any class Nest can construct and inject, most commonly marked with @Injectable().
Providers must be registered in a module's providers array to be constructible there.
Providers are singletons by default; REQUEST and TRANSIENT scopes exist for special cases.
Providers include services, repositories, factories, and more, not just classes named Service.
Pro Tip
Reach for REQUEST-scoped providers sparingly, they opt a whole branch of the dependency graph out of Nest's singleton optimizations. Prefer passing request-specific data as method arguments over changing a provider's scope.
You now understand what a NestJS provider is. Next, look specifically at NestJS Services, the most common kind of provider.