From HttpClientModule to provideHttpClient
Register the HTTP client with provideHttpClient() in standalone apps instead of importing HttpClientModule
CLI Migration Script
Overview
Angular's HTTP client was traditionally registered by importing HttpClientModule in an NgModule. In v14 you could use importProvidersFrom(HttpClientModule) in providers for standalone/hybrid apps. In v15, provideHttpClient() is the preferred API in bootstrap providers. HttpClientModule is deprecated as of v18—migrate to provideHttpClient(). This practice covers the migration and optional features like withFetch(), withInterceptors(), and withInterceptorsFromDi().
Migration guide
Unless you are an early adopter of standalone, wait for the standalone migration script introduced in v15.2 before changing your HTTP setup.
Use the standalone migration in 15.2 to bootstrap your application; it will move HttpClientModule into importProvidersFrom. Because provideHttpClient() is only usable with a standalone application, run the migration first, then remove HttpClientModule from importProvidersFrom and switch to provideHttpClient(). All options available with HttpClientModule are available with provideHttpClient(), so you won't introduce regressions.
withRequestsMadeViaParent() is introduced as a developer preview in v15.1—it's a new feature, so you can start adopting it even in preview if you need it; it's not available with HttpClientModule.
Functional interceptors are introduced in v15 but do not benefit from a migration script. To delay their manual migration, use withInterceptorsFromDi() with provideHttpClient() to support your existing class-based interceptors. Once the interceptor migration is done, you can switch to withInterceptors().
No changes to HTTP client setup.
XMLHttpRequest is not supported in all environments. You can use the withFetch() feature, even if still in developer preview.
No changes to HTTP client setup.
withFetch() is now stable. You can add it if you delayed the change due to the preview status of the feature.
HttpClientModule is deprecated; migrate to provideHttpClient().
withRequestsMadeViaParent() is now stable. You can add it if you delayed the change due to the preview status of the feature.
No changes to HTTP client setup.
provideHttpClient() is now provided by default. It won't affect existing applications. You'll need to add it explicitly if you need to pass options (such as withFetch()).
The Evolution
Code Comparison
Registering the HTTP client
import { NgModule } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { HttpClientModule } from '@angular/common/http';
@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, HttpClientModule ], bootstrap: [AppComponent]})export class AppModule {}import { bootstrapApplication } from '@angular/platform-browser';import { provideHttpClient } from '@angular/common/http';import { AppComponent } from './app.component';
bootstrapApplication(AppComponent, { providers: [provideHttpClient()]});v14: importProvidersFrom(HttpClientModule)
In Angular v14 you can use importProvidersFrom(HttpClientModule) in your app config or route providers for a standalone/hybrid setup, instead of importing HttpClientModule in an NgModule. In v15, provideHttpClient() is the preferred API.
HttpClientModule deprecated in v18
HttpClientModule is deprecated as of Angular v18. Use provideHttpClient() in your application providers instead. Run the standalone-bootstrap migration to switch from NgModule bootstrap to standalone bootstrap and update HTTP setup.
With functional interceptors
@NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ]})export class AppModule {}import { provideHttpClient, withInterceptors } from '@angular/common/http';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient( withInterceptors([authInterceptor]) ) ]});With DI-based (class) interceptors: withInterceptorsFromDi
To keep using class-based interceptors registered via HTTP_INTERCEPTORS with provideHttpClient(), add withInterceptorsFromDi(). Angular will then pick up any multi provider for HTTP_INTERCEPTORS from your app’s injector.
@NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]})export class AppModule {}import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';import { HTTP_INTERCEPTORS } from '@angular/common/http';import { AuthInterceptor } from './auth.interceptor';import { LoggingInterceptor } from './logging.interceptor';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient(withInterceptorsFromDi()), { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]});You can combine withInterceptorsFromDi() with withInterceptors() and other features:
provideHttpClient( withInterceptorsFromDi(), withInterceptors([authInterceptor]), withFetch())Fetch backend (optional)
// Default: XMLHttpRequest-basedimports: [HttpClientModule]import { provideHttpClient, withFetch } from '@angular/common/http';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient(withFetch()) ]});withFetch() in v16.1
withFetch() was available in developer preview in Angular v16.1. Use it with provideHttpClient() to switch from XMLHttpRequest to the Fetch API (e.g. for SSR or smaller bundle).
Why withFetch() over XMLHttpRequest?
The Fetch API is a more modern API than XMLHttpRequest and is available in environments where XMLHttpRequest is not supported (for example, some server-side or edge runtimes). Using withFetch() can simplify server-side rendering and reduce bundle size when XHR is not needed. withFetch() does have a few limitations: it does not produce upload progress events, so if your app relies on upload progress (e.g. HttpClient request with reportProgress: true for uploads), the default XHR-based backend may be preferable.
Using HttpClient (unchanged)
@Injectable({ providedIn: 'root' })export class UserService { private http = inject(HttpClient); getUsers() { return this.http.get<User[]>('/api/users'); }}@Injectable({ providedIn: 'root' })export class UserService { private http = inject(HttpClient); getUsers() { return this.http.get<User[]>('/api/users'); }}Key Differences
Benefits
No NgModule; fits bootstrapApplication
withInterceptors(), withFetch(), withXsrfConfiguration()
Provider function is analyzable
HttpClient usage unchanged
withInterceptors() for functional interceptors
provideHttpClient() options
NgModule compatibility
| NgModule | provideHttpClient() equivalent |
| --------------------------------------- | --------------------------------------------- |
| HttpClientModule | provideHttpClient(withInterceptorsFromDi()) |
| HttpClientJsonpModule | withJsonpSupport() |
| HttpClientXsrfModule.withOptions(...) | withXsrfConfiguration(...) |
| HttpClientXsrfModule.disable() | withNoXsrfProtection() |
- withInterceptors([...]): Register functional interceptors (see related practice).
- withInterceptorsFromDi(): Enable DI-based interceptors; any provider for
HTTP_INTERCEPTORS(multi: true) will be used. Use this to migrate class-based interceptors without rewriting them as functions. - withFetch(): Use the Fetch API instead of XMLHttpRequest (e.g. for SSR or smaller bundle). Available in developer preview in v16.1.
- withXsrfConfiguration(
{ ... }): Configure XSRF cookie/header names. - withNoXsrf(): Disable XSRF protection.
- withRequestsMadeViaParent(): Use the parent injector’s HttpClient for requests (useful in multi-injector setups so child injectors share the same client and interceptors).
Multi-injector configurations
When HttpClientModule is present in multiple injectors (e.g. root and a lazy-loaded module), the behavior of interceptors is poorly defined and depends on the exact options and provider/import ordering. Prefer provideHttpClient() for multi-injector configurations, as it has more stable behavior. For child injectors that should use the same HTTP client and interceptors as the parent, use withRequestsMadeViaParent() (see above).
withFetch() and SSR
Using withFetch() can simplify server-side rendering and reduce payload, since the Fetch API is available in Node and browsers.
From HttpClientModule to provideHttpClient
Register the HTTP client with provideHttpClient() in standalone apps instead of importing HttpClientModule
CLI Migration Script
Overview
Angular's HTTP client was traditionally registered by importing HttpClientModule in an NgModule. In v14 you could use importProvidersFrom(HttpClientModule) in providers for standalone/hybrid apps. In v15, provideHttpClient() is the preferred API in bootstrap providers. HttpClientModule is deprecated as of v18—migrate to provideHttpClient(). This practice covers the migration and optional features like withFetch(), withInterceptors(), and withInterceptorsFromDi().
Migration guide
Unless you are an early adopter of standalone, wait for the standalone migration script introduced in v15.2 before changing your HTTP setup.
Use the standalone migration in 15.2 to bootstrap your application; it will move HttpClientModule into importProvidersFrom. Because provideHttpClient() is only usable with a standalone application, run the migration first, then remove HttpClientModule from importProvidersFrom and switch to provideHttpClient(). All options available with HttpClientModule are available with provideHttpClient(), so you won't introduce regressions.
withRequestsMadeViaParent() is introduced as a developer preview in v15.1—it's a new feature, so you can start adopting it even in preview if you need it; it's not available with HttpClientModule.
Functional interceptors are introduced in v15 but do not benefit from a migration script. To delay their manual migration, use withInterceptorsFromDi() with provideHttpClient() to support your existing class-based interceptors. Once the interceptor migration is done, you can switch to withInterceptors().
No changes to HTTP client setup.
XMLHttpRequest is not supported in all environments. You can use the withFetch() feature, even if still in developer preview.
No changes to HTTP client setup.
withFetch() is now stable. You can add it if you delayed the change due to the preview status of the feature.
HttpClientModule is deprecated; migrate to provideHttpClient().
withRequestsMadeViaParent() is now stable. You can add it if you delayed the change due to the preview status of the feature.
No changes to HTTP client setup.
provideHttpClient() is now provided by default. It won't affect existing applications. You'll need to add it explicitly if you need to pass options (such as withFetch()).
The Evolution
Code Comparison
Registering the HTTP client
import { NgModule } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { HttpClientModule } from '@angular/common/http';
@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, HttpClientModule ], bootstrap: [AppComponent]})export class AppModule {}import { bootstrapApplication } from '@angular/platform-browser';import { provideHttpClient } from '@angular/common/http';import { AppComponent } from './app.component';
bootstrapApplication(AppComponent, { providers: [provideHttpClient()]});v14: importProvidersFrom(HttpClientModule)
In Angular v14 you can use importProvidersFrom(HttpClientModule) in your app config or route providers for a standalone/hybrid setup, instead of importing HttpClientModule in an NgModule. In v15, provideHttpClient() is the preferred API.
HttpClientModule deprecated in v18
HttpClientModule is deprecated as of Angular v18. Use provideHttpClient() in your application providers instead. Run the standalone-bootstrap migration to switch from NgModule bootstrap to standalone bootstrap and update HTTP setup.
With functional interceptors
@NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true } ]})export class AppModule {}import { provideHttpClient, withInterceptors } from '@angular/common/http';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient( withInterceptors([authInterceptor]) ) ]});With DI-based (class) interceptors: withInterceptorsFromDi
To keep using class-based interceptors registered via HTTP_INTERCEPTORS with provideHttpClient(), add withInterceptorsFromDi(). Angular will then pick up any multi provider for HTTP_INTERCEPTORS from your app’s injector.
@NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]})export class AppModule {}import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';import { HTTP_INTERCEPTORS } from '@angular/common/http';import { AuthInterceptor } from './auth.interceptor';import { LoggingInterceptor } from './logging.interceptor';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient(withInterceptorsFromDi()), { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true } ]});You can combine withInterceptorsFromDi() with withInterceptors() and other features:
provideHttpClient( withInterceptorsFromDi(), withInterceptors([authInterceptor]), withFetch())Fetch backend (optional)
// Default: XMLHttpRequest-basedimports: [HttpClientModule]import { provideHttpClient, withFetch } from '@angular/common/http';
bootstrapApplication(AppComponent, { providers: [ provideHttpClient(withFetch()) ]});withFetch() in v16.1
withFetch() was available in developer preview in Angular v16.1. Use it with provideHttpClient() to switch from XMLHttpRequest to the Fetch API (e.g. for SSR or smaller bundle).
Why withFetch() over XMLHttpRequest?
The Fetch API is a more modern API than XMLHttpRequest and is available in environments where XMLHttpRequest is not supported (for example, some server-side or edge runtimes). Using withFetch() can simplify server-side rendering and reduce bundle size when XHR is not needed. withFetch() does have a few limitations: it does not produce upload progress events, so if your app relies on upload progress (e.g. HttpClient request with reportProgress: true for uploads), the default XHR-based backend may be preferable.
Using HttpClient (unchanged)
@Injectable({ providedIn: 'root' })export class UserService { private http = inject(HttpClient); getUsers() { return this.http.get<User[]>('/api/users'); }}@Injectable({ providedIn: 'root' })export class UserService { private http = inject(HttpClient); getUsers() { return this.http.get<User[]>('/api/users'); }}Key Differences
Benefits
No NgModule; fits bootstrapApplication
withInterceptors(), withFetch(), withXsrfConfiguration()
Provider function is analyzable
HttpClient usage unchanged
withInterceptors() for functional interceptors
provideHttpClient() options
NgModule compatibility
| NgModule | provideHttpClient() equivalent |
| --------------------------------------- | --------------------------------------------- |
| HttpClientModule | provideHttpClient(withInterceptorsFromDi()) |
| HttpClientJsonpModule | withJsonpSupport() |
| HttpClientXsrfModule.withOptions(...) | withXsrfConfiguration(...) |
| HttpClientXsrfModule.disable() | withNoXsrfProtection() |
- withInterceptors([...]): Register functional interceptors (see related practice).
- withInterceptorsFromDi(): Enable DI-based interceptors; any provider for
HTTP_INTERCEPTORS(multi: true) will be used. Use this to migrate class-based interceptors without rewriting them as functions. - withFetch(): Use the Fetch API instead of XMLHttpRequest (e.g. for SSR or smaller bundle). Available in developer preview in v16.1.
- withXsrfConfiguration(
{ ... }): Configure XSRF cookie/header names. - withNoXsrf(): Disable XSRF protection.
- withRequestsMadeViaParent(): Use the parent injector’s HttpClient for requests (useful in multi-injector setups so child injectors share the same client and interceptors).
Multi-injector configurations
When HttpClientModule is present in multiple injectors (e.g. root and a lazy-loaded module), the behavior of interceptors is poorly defined and depends on the exact options and provider/import ordering. Prefer provideHttpClient() for multi-injector configurations, as it has more stable behavior. For child injectors that should use the same HTTP client and interceptors as the parent, use withRequestsMadeViaParent() (see above).
withFetch() and SSR
Using withFetch() can simplify server-side rendering and reduce payload, since the Fetch API is available in Node and browsers.