← Back to Articles         
HttpClientModule Configured Before Standalone Angular

HttpClientModule Configured Before Standalone Angular

Published on 01 Oct 2026     6 min read Angular
HTTP & Web API Integration

How Was HttpClientModule Configured Before Standalone Angular?

Before standalone APIs became the preferred approach, Angular applications were commonly organized using NgModules.

To use HttpClient, you imported HttpClientModule into an Angular module—typically the root AppModule.


1. What is HttpClientModule?

HttpClientModule is the traditional NgModule-based configuration that made Angular's HTTP services, including HttpClient, available through Angular's dependency-injection system.

It was imported from:

import { HttpClientModule } from '@angular/common/http';

The typical architecture was:

AppModule
   │
   ├── imports HttpClientModule
   │
   ↓
Angular DI
   │
   ↓
HttpClient available
   │
   ↓
ProductService
   │
   ↓
ASP.NET Core Web API

2. Full Simple Sample Program

Suppose our ASP.NET Core API is:

GET https://localhost:7001/api/products

Project Structure

src/
│
├── app/
│   ├── app.component.ts
│   ├── app.component.html
│   ├── app.module.ts
│   │
│   ├── product.ts
│   ├── product.service.ts
│   │
│   └── products/
│       ├── products.component.ts
│       └── products.component.html
│
└── main.ts

app.module.ts

This is the most important file for understanding the old approach.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';

@NgModule({
  declarations: [
    AppComponent,
    ProductsComponent
  ],

  imports: [
    BrowserModule,
    HttpClientModule
  ],

  providers: [],

  bootstrap: [
    AppComponent
  ]
})
export class AppModule {
}

product.ts

export interface Product {
  id: number;
  name: string;
  price: number;
}

product.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { Product } from './product';

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

  private apiUrl =
    'https://localhost:7001/api/products';

  constructor(private http: HttpClient) {
  }

  getProducts(): Observable<Product[]> {
    return this.http.get<Product[]>(this.apiUrl);
  }
}

products.component.ts

import { Component, OnInit } from '@angular/core';

import { Product } from '../product';
import { ProductService } from '../product.service';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html'
})
export class ProductsComponent implements OnInit {

  products: Product[] = [];

  constructor(
    private productService: ProductService
  ) {
  }

  ngOnInit(): void {

    this.productService
      .getProducts()
      .subscribe({
        next: (data) => {
          this.products = data;
        },
        error: (error) => {
          console.error(error);
        }
      });

  }
}

products.component.html

<h2>Products</h2>

<div *ngFor="let product of products">

  {{ product.name }}
  -
  ₹{{ product.price }}

</div>

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
}

app.component.html

<h1>Product Application</h1>

<app-products></app-products>

main.ts

The old application bootstrapped the root NgModule:

import { platformBrowserDynamic }
  from '@angular/platform-browser-dynamic';

import { AppModule }
  from './app/app.module';

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));

3. How Did HttpClientModule Work?

The key configuration was:

import { HttpClientModule }
  from '@angular/common/http';

and then:

@NgModule({

  imports: [
    BrowserModule,
    HttpClientModule
  ]

})
export class AppModule {
}

Importing HttpClientModule registered the HTTP-related providers needed for HttpClient.

Then Angular could inject HttpClient:

constructor(private http: HttpClient) {
}

Without the HTTP providers being configured, Angular's DI system could not satisfy the HttpClient dependency.


4. Complete Flow

main.ts
   ↓
bootstrapModule(AppModule)
   ↓
AppModule
   ↓
imports HttpClientModule
   ↓
HTTP providers registered
   ↓
HttpClient becomes injectable
   ↓
ProductService
   ↓
constructor(private http: HttpClient)
   ↓
http.get<Product[]>()
   ↓
HTTP GET
   ↓
ASP.NET Core Web API
   ↓
JSON Response
   ↓
Observable<Product[]>
   ↓
Component
   ↓
HTML

5. Why Was It Added to imports?

Because HttpClientModule was an NgModule.

NgModules were registered through the imports array:

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule
  ]
})

This is similar to how traditional Angular applications imported:

imports: [
  BrowserModule,
  HttpClientModule,
  FormsModule,
  ReactiveFormsModule
]

So the old mental model was:

Need Angular feature
       ↓
Find corresponding NgModule
       ↓
Import NgModule
       ↓
Add it to imports[]

6. Before Standalone vs Modern Standalone

This is the most important distinction.

Before Standalone

app.module.ts

import { HttpClientModule }
  from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule
  ]
})
export class AppModule {
}

main.ts

platformBrowserDynamic()
  .bootstrapModule(AppModule);

Modern Standalone

There is normally no need for AppModule.

app.config.ts

import { ApplicationConfig } from '@angular/core';
import { provideHttpClient }
  from '@angular/common/http';

export const appConfig: ApplicationConfig = {

  providers: [
    provideHttpClient()
  ]

};

main.ts

import { bootstrapApplication }
  from '@angular/platform-browser';

import { App }
  from './app/app';

import { appConfig }
  from './app/app.config';

bootstrapApplication(
  App,
  appConfig
)
.catch(err => console.error(err));

7. Side-by-Side Comparison

Before Standalone Modern Standalone
NgModule based Standalone APIs
AppModule app.config.ts
HttpClientModule provideHttpClient()
Added to imports[] Added to providers[]
bootstrapModule(AppModule) bootstrapApplication(App, appConfig)

The key change is:

OLD

AppModule
   ↓
imports[]
   ↓
HttpClientModule

became:

MODERN

ApplicationConfig
   ↓
providers[]
   ↓
provideHttpClient()

8. Does Using provideHttpClient() Change HttpClient?

No.

This is an important distinction.

Old configuration

HttpClientModule

Modern configuration

provideHttpClient()

But application services still use:

HttpClient

For example, old code:

constructor(private http: HttpClient) {
}

Modern code can still use constructor injection:

constructor(private http: HttpClient) {
}

or the newer inject() style:

private http = inject(HttpClient);

So:

Configuration changed
HttpClient itself remains the service you use

9. Easy Way to Remember

Think about it this way:

Old Angular

I need HTTP
    ↓
Import HTTP Module
    ↓
HttpClientModule
    ↓
AppModule imports[]
    ↓
Use HttpClient

Modern Angular

I need HTTP
    ↓
Provide HTTP functionality
    ↓
provideHttpClient()
    ↓
Application providers
    ↓
Use HttpClient

Or simply remember:

Before standalone:
HttpClientModule

Modern standalone:
provideHttpClient()

Actual HTTP service:
HttpClient

Key Points

  • Traditional Angular applications were based on NgModules.
  • HttpClientModule was imported from @angular/common/http.
  • It was typically added to the imports array of AppModule.
  • Importing it configured the providers required by HttpClient.
  • Services could then inject HttpClient.
  • The old application was commonly bootstrapped with:
bootstrapModule(AppModule)
  • Modern standalone Angular uses:
provideHttpClient()
  • The modern application is bootstrapped using:
bootstrapApplication()
  • HttpClientModule and HttpClient are not the same thing.
  • HttpClientModule was the traditional configuration mechanism; HttpClient is the service that actually makes HTTP requests.

Interview Questions and Answers

1. How was HttpClient configured before standalone Angular?

HttpClientModule was imported from @angular/common/http and added to the imports array of an NgModule, commonly AppModule.

@NgModule({
  imports: [
    HttpClientModule
  ]
})
export class AppModule {
}

2. What replaced HttpClientModule in modern standalone Angular?

The provider function:

provideHttpClient()

is the preferred modern configuration.

3. Where was HttpClientModule usually imported?

Usually in the root:

AppModule

although NgModule architecture could also configure HTTP through other appropriate modules.

4. Why was HttpClientModule placed inside imports[]?

Because HttpClientModule is an Angular NgModule, and dependent NgModules were registered through the imports metadata.

5. Did we inject HttpClientModule into services?

No.

We configured:

HttpClientModule

but injected:

HttpClient

For example:

constructor(private http: HttpClient) {
}

6. What is the main difference between the old and modern approaches?

Old:
AppModule → imports[] → HttpClientModule

Modern:
ApplicationConfig → providers[] → provideHttpClient()

Both ultimately allow application code to inject and use HttpClient.

7. What is the best short interview answer?

Before standalone Angular, HttpClient was configured by importing HttpClientModule from @angular/common/http and adding it to the imports array of an NgModule, typically AppModule. Modern standalone Angular instead uses provideHttpClient() in the application providers.

← Back to Articles