182
votes

When generating services in the Angular CLI, it is adding extra metadata with a 'provided in' property with a default of 'root' for the Injectable decorator.

@Injectable({
  providedIn: 'root',
})

What exactly does providedIn do? I am assuming this is making the service available like a 'global' type singleton service for the whole application, however, wouldn't be cleaner to declare such services in the provider array of the AppModule?

UPDATE:

For anyone else, the following paragraph provided another good explanation of it also, in particular if you want to provide your service to only a feature module.

There is now a new, recommended, way to register a provider, directly inside the @Injectable() decorator, using the new providedIn attribute. It accepts 'root' as a value or any module of your application. When you use 'root', your injectable will be registered as a singleton in the application, and you don’t need to add it to the providers of the root module. Similarly, if you use providedIn: UsersModule, the injectable is registered as a provider of the UsersModule without adding it to the providers of the module." - https://blog.ninja-squad.com/2018/05/04/what-is-new-angular-6/

UPDATE 2:

After further investigation, I have decided it is only useful to have providedIn: 'root'

If you want to provide a service in any module other than the root module, then you are better off using the providers array in the feature module's decorators, otherwise you will be plagued with circular dependencies. Interesting discussions to be had here - https://github.com/angular/angular-cli/issues/10170

6
I think your updates should be an answer (you can answer your own questions) instead of adding it to your question.PhoneixS
The most important part is SINGLETON, no one mentions it!Kyle Burkett

6 Answers

93
votes

providedIn: 'root' is the easiest and most efficient way to provide services since Angular 6:

  1. The service will be available application wide as a singleton with no need to add it to a module's providers array (like Angular <= 5).
  2. If the service is only used within a lazy loaded module it will be lazy loaded with that module
  3. If it is never used it will not be contained in the build (tree shaked).

For further informations consider reading the documentation and NgModule FAQs

Btw:

  1. If you don't want a application-wide singleton use the provider's array of a component instead.
  2. If you want to limit the scope so no other developer will ever use your service outside of a particular module, use the providers array of NgModule instead.
74
votes

From Docs

What is Injectable decorator?

Marks a class as available to Injector for creation.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class UserService {
}

The service itself is a class that the CLI generated and that's decorated with @Injectable().

What exactly does providedIn do?

Determines which injectors will provide the injectable, by either associating it with an @NgModule or other InjectorType, or by specifying that this injectable should be provided in the 'root' injector, which will be the application-level injector in most apps.

providedIn: Type<any> | 'root' | null

providedIn: 'root'

When you provide the service at the root level, Angular creates a single, shared instance of service and injects it into any class that asks for it. Registering the provider in the @Injectable() metadata also allows Angular to optimize an app by removing the service from the compiled app if it isn't used.

providedIn: Module

It's also possible to specify that a service should be provided in a particular @NgModule. For example, if you don't want a service to be available to applications unless they import a module you've created, you can specify that the service should be provided in the module

import { Injectable } from '@angular/core';
import { UserModule } from './user.module';

@Injectable({
  providedIn: UserModule,
})
export class UserService {
}

This method is preferred because it enables Tree-shaking (Tree shaking is a step in a build process that removes unused code from a code base) of the service if nothing injects it.

If it's not possible to specify in the service which module should provide it, you can also declare a provider for the service within the module:

import { NgModule } from '@angular/core';
import { UserService } from './user.service';

@NgModule({
  providers: [UserService],
})
export class UserModule {
}
68
votes

if you use providedIn, the injectable is registered as a provider of the Module without adding it to the providers of the module.

From Docs

The service itself is a class that the CLI generated and that's decorated with @Injectable. By default, this decorator is configured with a providedIn property, which creates a provider for the service. In this case, providedIn: 'root' specifies that the service should be provided in the root injector.

17
votes

providedIn tells Angular that the root injector is responsible for creating an instance of the your Service. Services that are provided this way are automatically made available to the entire application and don't need to be listed in any module.

Service classes can act as their own providers which is why defining them in the @Injectable decorator is all the registration you need.

11
votes

see Excellent explanation by @Nipuna,

I'd like to extend it by adding examples.

if you just use Injectable decorator without providedin property, like,

@Injectable()

then you would have to write service's name in respective Module's providers Array.

like this;

data.service.ts ↴

import { Injectable } from '@angular/core';

@Injectable()
export class DataService {
    constructor() {}

    // Code . . .
}

app.module.ts ↴

import { AppComponent } from './app.component';
import { DataService } from './core/data.service';

@NgModule({
    declarations: [AppComponent],
    providers: [DataService],    // ⟵ LOOK HERE WE PROVIDED IT
    imports: [...],
    bootstrap: [AppComponent],
})
export class AppModule {}

But, If you use providedIn: 'root', like this:

data.service.ts ↴

import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root',
})
export class DataService {
    constructor() {}

    // Code . . .
}

Then our module would look like this:

app.module.ts ↴

import { AppComponent } from './app.component';
import { DataService } from './core/data.service';

@NgModule({
    declarations: [AppComponent],
    providers: [],
    imports: [...],
    bootstrap: [AppComponent],
})
export class AppModule {}

see I didn't add DataService in providers array this time, because it's not needed.

Good Practices

This might come in handy, from Angular Guides

Do provide a service with the app root injector in the @Injectable decorator of the service.

Why? The Angular injector is hierarchical.

Why? When you provide the service to a root injector, that instance of the service is shared and available in every class that needs the service. This is ideal when a service is sharing methods or state.

Why? When you register a service in the @Injectable decorator of the service, optimization tools such as those used by the Angular CLI's production builds can perform tree shaking and remove services that aren't used by your app.

Why? This is not ideal when two different components need different instances of a service. In this scenario it would be better to provide the service at the component level that needs the new and separate instance.

4
votes

According to the Documentation:

Registering the provider in the @Injectable() metadata also allows Angular to optimize an app by removing the service from the compiled app if it isn't used.