One Instance to Rule Them All: Singleton Services in Angular

Learn about singleton services in Angular and how to control the scope of a service using the 'providedIn' property in the '@Injectable' decorator. Discover how to register services at the application level ('root') to ensure a single instance, and how to register them at the module level for a specific lifecycle. Understand when and why to use singleton services to efficiently manage state and share logic.

⚙️

Welcome! Let's see how Angular manages service instances.

/* Initializing service... */

What is a Singleton Service?

A Singleton Service is a service for which only one instance exists in the entire application. This is the default and most common behavior for services in Angular. It's perfect for managing application-wide state, like user authentication or a shopping cart, because every component gets the exact same service instance.

Understanding Service Scope

Service Scope determines where in your application a service instance is available. By controlling the scope, you can decide whether a service should be a singleton or if you need separate instances for different parts of your app (e.g., for each lazy-loaded module).

The Modern Way: `providedIn`

The modern way to define a service's scope is with the providedIn property in the @Injectable decorator. Setting providedIn: 'root' makes the service a singleton available everywhere. This method is preferred because it allows for tree-shaking, meaning the service is only included in the final bundle if it's actually used.

The Classic Way: Module `providers`

Alternatively, you can provide a service at the module level by adding it to the providers array of an @NgModule. If the module is the root `AppModule`, the service becomes a singleton. If it's a lazy-loaded module, a new instance of the service is created for that module.

Practice Zone


Interactive Test 1: Match the Scope

Drag the description to the correct scope definition.

Arrastra en el orden correspondiente.


Arrastra las opciones:

App-wide Singleton
Module-specific Instance

Completa el código:

providedIn: 'root'______
providers: [MyService]______
Unlock with Premium

Interactive Test 2: Configure the Service

Rellena los huecos en cada casilla.

// Singleton Service
@Injectable({ providedIn: '' })
export class AppService {}

// Module-level Service
@NgModule({
  providers: [  ]
})
export class FeatureModule {}
Unlock with Premium

Practice Example: Create a Singleton

Create a service named `CounterService` that is a singleton. It should have a `count` property and an `increment` method.

* Write the code below. Correct characters will be shown in green and incorrect ones in red.

import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CounterService { count = 0; increment() { this.count++; } }
Unlock with Premium

Knowledge Check

What is the primary benefit of using `providedIn: 'root'`?


Unlock with Premium

Services in a Real Angular App

Singleton services are the backbone of many Angular applications, used for everything from API calls to state management.


1. Centralized API Logic

A common use case is an `ApiService` that handles all communication with a backend. By making it a singleton, you ensure that all HTTP settings and headers are managed consistently across the app.

@Injectable({ providedIn: 'root' })
export class ApiService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get('/api/users');
  }
}

2. Simple State Management

For simple state needs, a singleton service can hold shared data. For example, a `ThemeService` could manage whether the app is in light or dark mode, and any component can inject it to read or update the theme.

@Injectable({ providedIn: 'root' })
export class ThemeService {
  isDarkMode = false;

  toggleTheme() {
    this.isDarkMode = !this.isDarkMode;
  }
}

Practical Takeaway: Use `providedIn: 'root'` for almost all your services. It's the simplest, most efficient way to manage shared logic and state in Angular. Only consider other scopes for advanced, specific use cases.

Service Concepts Glossary

Singleton
A design pattern that ensures a class has only one instance and provides a global point of access to it.
@Injectable()
A decorator that marks a class as available to be provided and injected as a dependency.
providedIn: 'root'
A property within `@Injectable` that registers the service with the application's root injector, making it a singleton.
Injector
An object in the Angular dependency injection system that is responsible for creating service instances and injecting them into components and other services.
Tree-shaking
A build optimization step that removes unused code from the final application bundle, reducing its size.