Overview
The @Injectable decorator marks a class as available to be provided and injected as a dependency. It enables Angular’s dependency injection system to provide instances of the class where needed.
Signature
@ Injectable ( options ?: Injectable ): TypeDecorator
Parameters
Optional configuration object that determines how and where the service is provided.
Injectable Options
providedIn
providedIn
'root' | 'platform' | null
Determines which injector provides the injectable.
'root' - Provided in the root injector (application-level, singleton)
'platform' - Provided in the platform injector (shared across apps)
null - Not automatically provided, must be added to a providers array
@ Injectable ({ providedIn: 'root' })
The providedIn: 'any' option is deprecated. Use 'root' instead.
Basic Service Example
import { Injectable } from '@angular/core' ;
@ Injectable ({
providedIn: 'root'
})
export class UserService {
private users : string [] = [];
addUser ( name : string ) {
this . users . push ( name );
}
getUsers () : string [] {
return this . users ;
}
getUserCount () : number {
return this . users . length ;
}
}
Service with Dependencies
import { Injectable } from '@angular/core' ;
import { HttpClient } from '@angular/common/http' ;
import { Observable } from 'rxjs' ;
@ Injectable ({
providedIn: 'root'
})
export class DataService {
private apiUrl = 'https://api.example.com' ;
constructor ( private http : HttpClient ) {}
fetchData < T >( endpoint : string ) : Observable < T > {
return this . http . get < T >( ` ${ this . apiUrl } / ${ endpoint } ` );
}
postData < T >( endpoint : string , data : any ) : Observable < T > {
return this . http . post < T >( ` ${ this . apiUrl } / ${ endpoint } ` , data );
}
}
Using Services in Components
import { Component , OnInit } from '@angular/core' ;
import { UserService } from './user.service' ;
@ Component ({
selector: 'app-root' ,
standalone: true ,
template: `
<div>
<h2>Users ({{userCount}})</h2>
<ul>
<li *ngFor="let user of users">{{user}}</li>
</ul>
<button (click)="addUser()">Add User</button>
</div>
`
})
export class AppComponent implements OnInit {
users : string [] = [];
userCount = 0 ;
constructor ( private userService : UserService ) {}
ngOnInit () {
this . users = this . userService . getUsers ();
this . userCount = this . userService . getUserCount ();
}
addUser () {
this . userService . addUser ( `User ${ this . userCount + 1 } ` );
this . users = this . userService . getUsers ();
this . userCount = this . userService . getUserCount ();
}
}
Component-Level Providers
import { Injectable } from '@angular/core' ;
@ Injectable ()
export class NotificationService {
notifications : string [] = [];
add ( message : string ) {
this . notifications . push ( message );
}
clear () {
this . notifications = [];
}
}
notification.component.ts
import { Component } from '@angular/core' ;
import { NotificationService } from './notification.service' ;
@ Component ({
selector: 'app-notifications' ,
standalone: true ,
providers: [ NotificationService ], // Component-specific instance
template: `
<div>
<div *ngFor="let msg of notificationService.notifications">
{{msg}}
</div>
<button (click)="addNotification()">Add</button>
<button (click)="notificationService.clear()">Clear</button>
</div>
`
})
export class NotificationComponent {
constructor ( public notificationService : NotificationService ) {}
addNotification () {
this . notificationService . add ( `Notification at ${ new Date (). toLocaleTimeString () } ` );
}
}
When provided in a component, each instance of the component gets its own instance of the service.
Factory Providers
import { Injectable , InjectionToken } from '@angular/core' ;
export const IS_PRODUCTION = new InjectionToken < boolean >( 'IS_PRODUCTION' );
@ Injectable ()
export class Logger {
constructor ( private isProduction : boolean ) {}
log ( message : string ) {
if ( ! this . isProduction ) {
console . log ( message );
}
}
error ( message : string ) {
console . error ( message );
}
}
export function loggerFactory ( isProduction : boolean ) {
return new Logger ( isProduction );
}
import { ApplicationConfig } from '@angular/core' ;
import { Logger , loggerFactory , IS_PRODUCTION } from './logger.service' ;
export const appConfig : ApplicationConfig = {
providers: [
{ provide: IS_PRODUCTION , useValue: false },
{
provide: Logger ,
useFactory: loggerFactory ,
deps: [ IS_PRODUCTION ]
}
]
};
Class Providers with useClass
import { Injectable } from '@angular/core' ;
export abstract class ConfigService {
abstract get apiUrl () : string ;
}
@ Injectable ()
export class DevelopmentConfigService implements ConfigService {
get apiUrl () {
return 'https://dev-api.example.com' ;
}
}
@ Injectable ()
export class ProductionConfigService implements ConfigService {
get apiUrl () {
return 'https://api.example.com' ;
}
}
import { ApplicationConfig } from '@angular/core' ;
import { ConfigService , DevelopmentConfigService } from './config.service' ;
export const appConfig : ApplicationConfig = {
providers: [
{
provide: ConfigService ,
useClass: DevelopmentConfigService
}
]
};
Value Providers
import { InjectionToken } from '@angular/core' ;
export const API_CONFIG = new InjectionToken < ApiConfig >( 'API_CONFIG' );
export interface ApiConfig {
apiUrl : string ;
timeout : number ;
retries : number ;
}
import { ApplicationConfig } from '@angular/core' ;
import { API_CONFIG , ApiConfig } from './constants' ;
const apiConfig : ApiConfig = {
apiUrl: 'https://api.example.com' ,
timeout: 5000 ,
retries: 3
};
export const appConfig : ApplicationConfig = {
providers: [
{ provide: API_CONFIG , useValue: apiConfig }
]
};
Usage:
import { Injectable , inject } from '@angular/core' ;
import { API_CONFIG , ApiConfig } from './constants' ;
@ Injectable ({ providedIn: 'root' })
export class ApiService {
private config = inject ( API_CONFIG );
constructor () {
console . log ( `API URL: ${ this . config . apiUrl } ` );
}
}
Inject Function
import { Injectable , inject } from '@angular/core' ;
import { HttpClient } from '@angular/common/http' ;
import { API_CONFIG } from './constants' ;
@ Injectable ({
providedIn: 'root'
})
export class ModernService {
private http = inject ( HttpClient );
private config = inject ( API_CONFIG );
fetchData () {
return this . http . get ( ` ${ this . config . apiUrl } /data` );
}
}
The inject() function is the modern way to inject dependencies. It can be used in constructors, field initializers, and factory functions.
Service Lifecycle
import { Injectable , OnDestroy } from '@angular/core' ;
import { interval , Subscription } from 'rxjs' ;
@ Injectable ({
providedIn: 'root'
})
export class CleanupService implements OnDestroy {
private subscription : Subscription ;
constructor () {
this . subscription = interval ( 1000 ). subscribe ( n => {
console . log ( `Tick: ${ n } ` );
});
}
ngOnDestroy () {
// Clean up resources
if ( this . subscription ) {
this . subscription . unsubscribe ();
}
}
}
Services provided in 'root' are singletons and live for the entire application lifetime. They won’t be destroyed until the app is closed. Implement OnDestroy for cleanup, but be aware it may not be called for root services.
Testing Services
import { TestBed } from '@angular/core/testing' ;
import { UserService } from './user.service' ;
describe ( 'UserService' , () => {
let service : UserService ;
beforeEach (() => {
TestBed . configureTestingModule ({
providers: [ UserService ]
});
service = TestBed . inject ( UserService );
});
it ( 'should be created' , () => {
expect ( service ). toBeTruthy ();
});
it ( 'should add users' , () => {
service . addUser ( 'John' );
expect ( service . getUserCount ()). toBe ( 1 );
expect ( service . getUsers ()). toContain ( 'John' );
});
});
Provider Scopes
Scope Description Lifetime providedIn: 'root'Application-level singleton Entire app providedIn: 'platform'Platform-level singleton All apps on page Component providers New instance per component Component lifetime Module providers Shared in module scope Module lifetime
Best Practices
Use providedIn: 'root' for application-wide services
Use component providers for component-specific state
Implement OnDestroy for cleanup in services with subscriptions
Use inject() function for modern dependency injection
Create abstract classes for service interfaces
Avoid circular dependencies between services
Don’t store component-specific state in root services
Be careful with service constructors - keep them lightweight
Always unsubscribe from observables to prevent memory leaks
See Also
Dependency Injection Learn DI fundamentals
Hierarchical Injectors Understand injector hierarchy
Creating Services Service creation guide
Providers Configure providers