adev/src/content/guide/di/creating-and-using-services.md
Services are reusable pieces of code that you can share across your Angular application. You commonly use them to handle data fetching, business logic, or other functionality that multiple components need to access.
You can create a service using the Angular CLI with the following command:
ng generate service CUSTOM_NAME
This command creates a dedicated CUSTOM_NAME.ts file in your src directory.
You can also manually create a service by adding the @Injectable() decorator to a TypeScript class. This tells Angular that you can use the class as an injectable dependency.
The following example defines a service that allows users to add and retrieve data:
import {Injectable} from '@angular/core';
@Injectable({providedIn: 'root'})
export class BasicDataStore {
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data];
}
}
When you use @Injectable({ providedIn: 'root' }) in your service, Angular:
This is the recommended approach for most services.
@Service decoratorIMPORTANT: The @Service decorator is in developer preview. Its API may change before becoming stable.
For the common case of a singleton service available throughout your application, Angular provides the @Service decorator as a more ergonomic alternative to @Injectable({providedIn: 'root'}).
The earlier BasicDataStore example can be rewritten with @Service:
import {Service} from '@angular/core';
@Service()
export class BasicDataStore {
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data];
}
}
This behaves the same as the @Injectable({providedIn: 'root'}) version above: Angular creates a single instance, makes it available everywhere, and tree-shakes it from the bundle if it is never injected.
If you need to control how the singleton is created, for example, to swap in a different implementation depending on the environment, pass a factory function.
The factory runs in an injection context, so you can use inject() inside it to read other dependencies.
The following Analytics service is a no-op locally so events don't pollute the console during development. In production, the factory reads an ANALYTICS_ENABLED token and returns a GoogleAnalytics subclass that forwards events to the real tracker:
import {inject, InjectionToken, Service} from '@angular/core';
import {ANALYTICS_ENABLED} from './token';
@Service({
factory: () => (inject(ANALYTICS_ENABLED) ? new GoogleAnalytics() : new Analytics()),
})
export class Analytics {
track(event: string, payload?: Record<string, unknown>) {
// No-op by default.
}
}
class GoogleAnalytics extends Analytics {
override track(event: string, payload?: Record<string, unknown>) {
// Dispatches an analytics event to Google Analytics
}
}
NOTE: The factory option replaces the useClass, useValue, useExisting, and useFactory options of @Injectable. If you need any of those, keep using @Injectable.
By default, @Service provides the class at the root injector. If you want to provide it manually, for example, to scope it to a specific route or component, set autoProvided: false:
import {Service} from '@angular/core';
@Service({autoProvided: false})
export class AnalyticsLogger {
trackEvent(name: string) {
console.log('event:', name);
}
}
You are then responsible for adding the service to a providers array, just like with a plain @Injectable():
@Service vs @InjectableReach for @Service when you are creating a new singleton class that uses inject() for its dependencies. Keep using @Injectable when you need any of the following:
@Service only supports the inject() function.useClass, useValue, useExisting, or useFactory. @Service exposes a single factory option instead.providedIn: 'platform'.Once you've created a service with providedIn: 'root', you can inject it anywhere in your application using the inject() function from @angular/core.
import {Component, inject} from '@angular/core';
import {BasicDataStore} from './basic-data-store';
@Component({
selector: 'app-example',
template: `
<div>
<p>{{ dataStore.getData() }}</p>
<button (click)="dataStore.addData('More data')">Add more data</button>
</div>
`,
})
export class Example {
dataStore = inject(BasicDataStore);
}
import {inject, Injectable} from '@angular/core';
import {AdvancedDataStore} from './advanced-data-store';
@Injectable({
providedIn: 'root',
})
export class BasicDataStore {
private advancedDataStore = inject(AdvancedDataStore);
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data, ...this.advancedDataStore.getData()];
}
}
While providedIn: 'root' covers most use cases, Angular also provides additional ways you can configure services for more specialized scenarios:
You can learn more about these advanced patterns in the next guide: defining dependency providers.