Provider Configuration Evolution
From NgModule providers to bootstrapApplication providers, provideRouter, provideHttpClient, route providers, and importProvidersFrom
Overview
Angular provider configuration has evolved from NgModule-based providers (providers array in @NgModule) to standalone provider APIs: bootstrapApplication with a providers array, provideRouter, provideHttpClient, route-level providers, and importProvidersFrom to pull providers from an NgModule. This practice summarizes the evolution and how to configure providers in modern Angular.
The Evolution
Providers declared in @NgModule({ providers: [...] }); imported via imports array.
Root providers in bootstrapApplication(Component, { providers: [...] }); provideRouter, provideHttpClient, etc.
Code Comparison
Root providers: NgModule vs bootstrapApplication
@NgModule({ declarations: [AppComponent], imports: [BrowserModule, RouterModule.forRoot(routes), HttpClientModule], providers: [ UserService, { provide: API_URL, useValue: 'https://api.example.com' } ], bootstrap: [AppComponent]})export class AppModule {}bootstrapApplication(AppComponent, { providers: [ UserService, { provide: API_URL, useValue: 'https://api.example.com' }, provideRouter(routes), provideHttpClient() ]});Router and HttpClient
@NgModule({ imports: [ BrowserModule, RouterModule.forRoot(routes), HttpClientModule ], ...})export class AppModule {}bootstrapApplication(AppComponent, { providers: [ provideRouter(routes), provideHttpClient() ]});Using NgModule providers in standalone app: importProvidersFrom
@NgModule({ imports: [SomeFeatureModule], // brings in providers from module ...})export class AppModule {}import { importProvidersFrom } from '@angular/core';
bootstrapApplication(AppComponent, { providers: [ importProvidersFrom(SomeFeatureModule) ]});Route-level providers
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)}// AdminModule has providers: [AdminService]{ path: 'admin', loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes), providers: [AdminService]}// Or in child route configprovidedIn: 'root' (unchanged)
@Injectable({ providedIn: 'root' })export class UserService {}@Injectable({ providedIn: 'root' })export class UserService {}// No change; works with bootstrapApplicationKey Differences
Benefits
No NgModule required for root config
Provider functions are analyzable
Mix provideRouter, provideHttpClient, custom providers
Providers per route for lazy scope
importProvidersFrom for existing modules
Provider configuration today
- Root: Use
bootstrapApplication(AppComponent, { providers: [...] }). AddprovideRouter(routes),provideHttpClient(), and app-wide services. - Route: Use
providers: [MyService]on a route so the service is available only for that route (and children) and is destroyed when leaving the route. - NgModule reuse: Use
importProvidersFrom(MyModule)in the root or route providers array to pull in that module's providers without importing the module for declarations. - Tree-shakeable: Keep
@Injectable({ providedIn: 'root' })for services used app-wide; they are tree-shaken if unused.
Route providers and lazy loading
Route-level providers are created when the route is activated and destroyed when it is left. Use them for feature-specific services that should not live in the root injector.
Provider Configuration Evolution
From NgModule providers to bootstrapApplication providers, provideRouter, provideHttpClient, route providers, and importProvidersFrom
Overview
Angular provider configuration has evolved from NgModule-based providers (providers array in @NgModule) to standalone provider APIs: bootstrapApplication with a providers array, provideRouter, provideHttpClient, route-level providers, and importProvidersFrom to pull providers from an NgModule. This practice summarizes the evolution and how to configure providers in modern Angular.
The Evolution
Providers declared in @NgModule({ providers: [...] }); imported via imports array.
Root providers in bootstrapApplication(Component, { providers: [...] }); provideRouter, provideHttpClient, etc.
Code Comparison
Root providers: NgModule vs bootstrapApplication
@NgModule({ declarations: [AppComponent], imports: [BrowserModule, RouterModule.forRoot(routes), HttpClientModule], providers: [ UserService, { provide: API_URL, useValue: 'https://api.example.com' } ], bootstrap: [AppComponent]})export class AppModule {}bootstrapApplication(AppComponent, { providers: [ UserService, { provide: API_URL, useValue: 'https://api.example.com' }, provideRouter(routes), provideHttpClient() ]});Router and HttpClient
@NgModule({ imports: [ BrowserModule, RouterModule.forRoot(routes), HttpClientModule ], ...})export class AppModule {}bootstrapApplication(AppComponent, { providers: [ provideRouter(routes), provideHttpClient() ]});Using NgModule providers in standalone app: importProvidersFrom
@NgModule({ imports: [SomeFeatureModule], // brings in providers from module ...})export class AppModule {}import { importProvidersFrom } from '@angular/core';
bootstrapApplication(AppComponent, { providers: [ importProvidersFrom(SomeFeatureModule) ]});Route-level providers
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)}// AdminModule has providers: [AdminService]{ path: 'admin', loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes), providers: [AdminService]}// Or in child route configprovidedIn: 'root' (unchanged)
@Injectable({ providedIn: 'root' })export class UserService {}@Injectable({ providedIn: 'root' })export class UserService {}// No change; works with bootstrapApplicationKey Differences
Benefits
No NgModule required for root config
Provider functions are analyzable
Mix provideRouter, provideHttpClient, custom providers
Providers per route for lazy scope
importProvidersFrom for existing modules
Provider configuration today
- Root: Use
bootstrapApplication(AppComponent, { providers: [...] }). AddprovideRouter(routes),provideHttpClient(), and app-wide services. - Route: Use
providers: [MyService]on a route so the service is available only for that route (and children) and is destroyed when leaving the route. - NgModule reuse: Use
importProvidersFrom(MyModule)in the root or route providers array to pull in that module's providers without importing the module for declarations. - Tree-shakeable: Keep
@Injectable({ providedIn: 'root' })for services used app-wide; they are tree-shaken if unused.
Route providers and lazy loading
Route-level providers are created when the route is activated and destroyed when it is left. Use them for feature-specific services that should not live in the root injector.