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 @Service() 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 {Service} from '@angular/core';
@Service()
export class BasicDataStore {
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data];
}
}
Services are provisioned at the root level by default. When a service is provided globally, Angular guarantees three main benefits:
@Service vs @Injectable decoratorThe @Service decorator serves as a modern, ergonomic shorthand for the traditional @Injectable({ providedIn: 'root' }) syntax.
Use this quick reference to decide which decorator fits your scenario:
| Feature / Requirement | @Service | @Injectable |
|---|---|---|
inject() function support | Yes | Yes |
| Constructor-based DI | ❌ No | Yes |
| Implicit root singleton provider | Yes | ❌ No (requires {providedIn: 'root'}) |
Advanced provider keys (useClass, etc.) | ❌ No | Yes |
| Custom initialization factories | Yes | Yes |
Non-root scopes (platform, etc.) | ❌ No | Yes |
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, Service} from '@angular/core';
import {AdvancedDataStore} from './advanced-data-store';
@Service()
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.