Question

How to Fix 'No Provider for HttpClient' in Angular

typescriptangular

Question

After upgrading an Angular application from Angular 4.4 to Angular 5.x, I replaced usages of HttpModule and Http with HttpClientModule and HttpClient. After that, the application started throwing this error:

Error: StaticInjectorError[HttpClient]:
  StaticInjectorError[HttpClient]:
    NullInjectorError: No provider for HttpClient!

In app.module.ts, HttpClientModule appears to be imported correctly:

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

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

I also added HttpModule again to make sure the issue was not caused by a missing dependency, but that did not solve the problem.

I am not sure where this error is coming from or how to trace it properly. I also see this warning during the build, and I am wondering whether it is related:

There are multiple modules with names that only differ in casing.
...
D:\XXX\node_modules\@angular\Common\esm5\http.js
D:\XXX\node_modules\@angular\common\esm5\http.js

Relevant environment details:

  • Angular 5.0.0 / 5.0.1 / 5.1 beta
  • Node 8.5.0
  • Windows
  • Custom Webpack setup

What causes Angular to report "No provider for HttpClient" even when HttpClientModule is imported, and how can it be fixed correctly?

Short Answer

By the end of this page, you will understand how Angular dependency injection provides HttpClient, why importing HttpClientModule in the correct module matters, and how build issues such as incorrect import casing can still cause the "No provider for HttpClient" error even when your code looks correct.

Concept

Angular uses dependency injection (DI) to create objects such as services. HttpClient is not something Angular creates automatically by magic. It becomes available only when Angular sees the provider setup from HttpClientModule.

When you write code like this:

constructor(private http: HttpClient) {}

Angular checks its injector and asks:

  • Do I know how to create HttpClient?
  • Was the module that provides it imported?
  • Am I in the right injector scope?

If the answer is no, Angular throws:

NullInjectorError: No provider for HttpClient!

Why this matters

This is a core Angular concept, not just an HTTP issue. The same pattern applies to many Angular features:

  • forms modules provide form directives
  • router modules provide routing services
  • HTTP modules provide HttpClient
  • feature modules can have their own providers

So the real lesson is:

  • Angular features often require module imports
  • services are resolved through dependency injection
  • wrong imports, wrong module scope, or duplicated builds can break DI

In this specific case

With Angular 4.3+, the newer HTTP API is:

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

The older API is:

import { HttpModule } from '@angular/http';
import { Http } from '@angular/http';

These are different systems. Importing HttpModule does not provide HttpClient.

Also, the warning about this path difference is important:

  • @angular/Common/...
  • @angular/common/...

On Windows, that may still build, but Webpack can treat them as separate modules. That can lead to Angular loading duplicate or mismatched module definitions, which can cause provider registration to fail in surprising ways.

Mental Model

Think of Angular's injector as a tool cabinet.

  • HttpClient is a tool you want to use.
  • HttpClientModule is the instruction that tells Angular to put that tool in the cabinet.
  • Your component or service asks for the tool.

If the tool was never added to the cabinet, Angular says:

  • No provider for HttpClient

Now imagine you accidentally label one shelf as common and another as Common. On some systems those may be treated differently. You may think the tool is in the cabinet, but Angular is looking in one shelf while the tool was registered in another. That is why inconsistent import casing can produce confusing dependency injection errors.

Take Quiz

Syntax and Examples

The core syntax for using HttpClient is:

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

And in your root module:

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

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

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

Then in a service:

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

@Injectable()
export class UserService {
  constructor(private http: HttpClient) {}

  getUsers(): Observable<any> {
    return this.http.get('/api/users');
  }
}

Important rule

If you inject HttpClient, you must import:

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

Importing this older module is not enough:

import { HttpModule } from '@angular/http';

That only supports the old Http service.

Correct vs incorrect

Incorrect

import { HttpModule } from '@angular/http';
import { HttpClient } from '@angular/common/http';

This mixes the old module with the new service.

Correct

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

Casing also matters

Always import Angular packages using the exact lowercase package name:

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

Not:

import { HttpModule } from '@angular/Http';
import { Something } from '@angular/Common/http';

Even one incorrect uppercase letter can create build and DI problems.

Step by Step Execution

Consider this small example:

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

@Injectable()
export class ProductService {
  constructor(private http: HttpClient) {}
}

And this module:

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

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

What happens step by step

  1. Angular starts the application with AppModule.
  2. Angular reads the imports array.
  3. BrowserModule is registered.
  4. HttpClientModule is not registered.
  5. Angular later tries to create ProductService.
  6. It sees the constructor requires HttpClient.
  7. Angular asks the injector for a provider for HttpClient.
  8. No provider exists.
  9. Angular throws:
No provider for HttpClient

Now the fixed version

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

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

Now the flow changes:

  1. Angular starts AppModule.
  2. It imports BrowserModule and HttpClientModule.
  3. HttpClientModule registers the providers needed for HttpClient.
  4. Angular creates ProductService.
  5. It sees HttpClient in the constructor.
  6. The injector finds the provider.
  7. Service creation succeeds.

Why the original issue can still happen

Even if HttpClientModule appears in AppModule, the error may still occur if:

  • the wrong module is bootstrapped
  • the service lives in a module that does not see that import
  • the build system includes duplicated Angular packages
  • some imports use incorrect casing like Common instead of common

That last case matches the warning shown in the question.

Real World Use Cases

Dependency injection and module-provided services appear everywhere in Angular apps.

API services

Most applications wrap HttpClient in services:

this.http.get('/api/orders')
this.http.post('/api/login', credentials)

If HttpClientModule is missing, all API communication fails.

Feature modules

Large apps split code into modules such as:

  • AdminModule
  • UserModule
  • SharedModule

If services are declared and used across these modules, understanding where providers come from becomes essential.

Testing

In tests, developers often replace HttpClientModule with HttpClientTestingModule so requests can be mocked safely.

Migration work

When upgrading Angular versions, teams often move from old APIs to new ones. During migrations, mixed imports such as Http + HttpClient are common sources of errors.

Build tooling

In real projects, custom Webpack or legacy build pipelines can accidentally duplicate Angular packages or resolve imports inconsistently. That can lead to injector errors that look like simple coding mistakes but are actually build configuration problems.

Take Quiz

Real Codebase Usage

In real Angular codebases, developers usually handle this concept through a few common patterns.

1. Import framework modules only once in the correct place

Usually, root-level framework modules are imported in AppModule:

imports: [BrowserModule, HttpClientModule, AppRoutingModule]

This makes shared infrastructure available app-wide.

2. Keep HTTP logic inside services

Instead of making HTTP calls in components, developers write services:

@Injectable()
export class NotificationService {
  constructor(private http: HttpClient) {}

  load() {
    return this.http.get('/api/notifications');
  }
}

This keeps components simpler and easier to test.

3. Use guard clauses and validation around responses

A service might validate parameters before making requests:

getUser(id: number) {
  if (!id) {
    throw new Error('User id is required');
  }

  return this.http.get(`/api/users/${id}`);
}

4. Centralize configuration

Real applications often use base URLs from configuration:

private apiUrl = '/api/users';

5. Error handling with RxJS

Developers usually add error handling to HTTP requests:

return this.http.get(this.apiUrl).catch(err => {
  console.error(err);
  return Observable.throw(err);
});

6. Avoid mixing old and new HTTP APIs

In mature codebases, teams standardize on one HTTP approach. During migration, they remove the old @angular/http imports to avoid confusion.

7. Watch for import hygiene

Teams often enforce consistent import casing and path style through linting and code review, because small path differences can break builds or create duplicate module instances.

Common Mistakes

1. Importing HttpModule but injecting HttpClient

Broken code:

import { HttpModule } from '@angular/http';
import { HttpClient } from '@angular/common/http';

Why it fails:

  • HttpModule provides the old Http
  • it does not provide HttpClient

Fix:

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

2. Importing HttpClientModule in the wrong module

If the app bootstraps AppModule but you imported HttpClientModule somewhere else that is never loaded, Angular still will not find the provider.

Fix:

  • import it in the module that is actually used
  • for app-wide usage, put it in AppModule

3. Wrong import casing

Broken code:

import { HttpModule } from '@angular/Http';
import { Something } from '@angular/Common/http';

Why it fails:

  • build tools may treat these as different modules
  • this can cause duplicate Angular package loading

Fix:

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

4. Mixing old and new HTTP APIs during migration

Broken pattern:

import { Http } from '@angular/http';
import { HttpClient } from '@angular/common/http';

Why it is risky:

  • creates confusion
  • increases chances of incorrect providers and inconsistent code

Fix:

  • migrate fully to HttpClient where possible
  • remove old HttpModule usage when no longer needed

5. Forgetting to rebuild vendor bundles

With custom Webpack setups, especially DLL/vendor builds, old cached bundles may still point to previous Angular modules.

Fix:

  • clean build output
  • rebuild vendor bundle
  • restart the dev server

6. Assuming Windows casing does not matter

Windows file systems are often case-insensitive, but bundlers and module resolvers can still warn or behave inconsistently.

Fix:

  • treat package import casing as strict
  • search the project for @angular/Common and similar mistakes

7. Providing HttpClient manually

Beginners sometimes try this:

providers: [HttpClient]

Why this is wrong:

  • HttpClient depends on other internal providers
  • HttpClientModule configures the whole dependency chain

Fix:

  • import HttpClientModule
  • do not manually provide HttpClient

Comparisons

ConceptOld APINew APIWhen to use
Angular HTTP moduleHttpModule from @angular/httpHttpClientModule from @angular/common/httpUse HttpClientModule in Angular 4.3+
Injected serviceHttpHttpClientPrefer HttpClient
Response handlingManual parsing often neededJSON handling is more convenientPrefer HttpClient
Provider sourceHttpModuleHttpClientModuleMust match the service you inject

HttpModule vs HttpClientModule

FeatureHttpModuleHttpClientModule
Package@angular/http@angular/common/http
StatusOlder APIModern Angular HTTP API
Injected classHttpHttpClient
Should be used for new codeNoYes

Module import vs provider error

SituationResult
HttpClient injected and HttpClientModule imported correctlyWorks
HttpClient injected but only HttpModule importedNo provider for HttpClient
Correct import in code but wrong path casing in buildMay cause duplicate modules or injector issues
Manually adding HttpClient to providersUsually incorrect setup
Take Quiz

Cheat Sheet

// New Angular HTTP API
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';

// Old Angular HTTP API
import { HttpModule } from '@angular/http';
import { Http } from '@angular/http';

Rules

  • If you inject HttpClient, import HttpClientModule
  • HttpModule does not provide HttpClient
  • Use exact lowercase package paths like @angular/common/http
  • Avoid mixing Http and HttpClient unless you are migrating carefully
  • In custom Webpack setups, rebuild vendor bundles after Angular upgrades

Quick fix checklist

  • Check AppModule imports
  • Search project for @angular/Common or other wrong casing
  • Search project for old Http imports
  • Remove stale build artifacts
  • Rebuild vendor bundle and restart dev server
  • Make sure the module containing HttpClientModule is actually loaded

Typical correct setup

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

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

Typical service

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

FAQ

Why do I get "No provider for HttpClient" even though I imported HttpClientModule?

Usually because the module import is in the wrong place, the wrong module is being bootstrapped, or the build has duplicated Angular packages due to path or casing issues.

Does HttpModule provide HttpClient?

No. HttpModule provides the older Http service. HttpClient requires HttpClientModule.

Can incorrect import casing really cause Angular DI errors?

Yes. With some build tools, @angular/Common and @angular/common can be treated as different module paths, leading to duplicate module instances and missing providers.

Should I keep both HttpModule and HttpClientModule during migration?

Only temporarily if some code still uses the old Http service. But new code should use HttpClient, and old imports should be removed as migration finishes.

Should I add HttpClient to the providers array manually?

No. Import HttpClientModule instead. It sets up the full provider chain correctly.

How do I find the casing problem in a large project?

Search for @angular/Common, @angular/Http, or any Angular import with uppercase letters in the package path. Standard Angular package names should be lowercase.

Why can this appear after an Angular upgrade?

Upgrades often change APIs, dependencies, and build behavior. If some files still use old imports or the build cache contains outdated bundles, injector errors can appear.

Take Quiz

Mini Project

Description

Build a small Angular service setup that fetches data from an API using HttpClient. This project demonstrates the exact dependency injection chain required for HTTP requests and helps you practice the correct module import pattern that prevents the "No provider for HttpClient" error.

Goal

Create a working Angular service that uses HttpClient to load a list of users, with the correct HttpClientModule setup in the application module.

Requirements

  • Import HttpClientModule in the root Angular module.
  • Create a service that injects HttpClient.
  • Add a method that fetches data from /api/users.
  • Create a component that calls the service on initialization.
  • Display the returned data or a loading message.
Take Quiz

Keep learning

Related questions

View more