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.
HttpClientis a tool you want to use.HttpClientModuleis 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.
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
- Angular starts the application with
AppModule. - Angular reads the
importsarray. BrowserModuleis registered.HttpClientModuleis not registered.- Angular later tries to create
ProductService. - It sees the constructor requires
HttpClient. - Angular asks the injector for a provider for
HttpClient. - No provider exists.
- 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:
- Angular starts
AppModule. - It imports
BrowserModuleandHttpClientModule. HttpClientModuleregisters the providers needed forHttpClient.- Angular creates
ProductService. - It sees
HttpClientin the constructor. - The injector finds the provider.
- 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
Commoninstead ofcommon
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:
AdminModuleUserModuleSharedModule
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.
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:
HttpModuleprovides the oldHttp- 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
HttpClientwhere possible - remove old
HttpModuleusage 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/Commonand similar mistakes
7. Providing HttpClient manually
Beginners sometimes try this:
providers: [HttpClient]
Why this is wrong:
HttpClientdepends on other internal providersHttpClientModuleconfigures the whole dependency chain
Fix:
- import
HttpClientModule - do not manually provide
HttpClient
Comparisons
| Concept | Old API | New API | When to use |
|---|---|---|---|
| Angular HTTP module | HttpModule from @angular/http | HttpClientModule from @angular/common/http | Use HttpClientModule in Angular 4.3+ |
| Injected service | Http | HttpClient | Prefer HttpClient |
| Response handling | Manual parsing often needed | JSON handling is more convenient | Prefer HttpClient |
| Provider source | HttpModule | HttpClientModule | Must match the service you inject |
HttpModule vs HttpClientModule
| Feature | HttpModule | HttpClientModule |
|---|---|---|
| Package | @angular/http | @angular/common/http |
| Status | Older API | Modern Angular HTTP API |
| Injected class | Http | HttpClient |
| Should be used for new code | No | Yes |
Module import vs provider error
| Situation | Result |
|---|---|
HttpClient injected and HttpClientModule imported correctly | Works |
HttpClient injected but only HttpModule imported | No provider for HttpClient |
| Correct import in code but wrong path casing in build | May cause duplicate modules or injector issues |
Manually adding HttpClient to providers | Usually incorrect setup |
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, importHttpClientModule HttpModuledoes not provideHttpClient- Use exact lowercase package paths like
@angular/common/http - Avoid mixing
HttpandHttpClientunless you are migrating carefully - In custom Webpack setups, rebuild vendor bundles after Angular upgrades
Quick fix checklist
- Check
AppModuleimports - Search project for
@angular/Commonor other wrong casing - Search project for old
Httpimports - Remove stale build artifacts
- Rebuild vendor bundle and restart dev server
- Make sure the module containing
HttpClientModuleis 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.
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
HttpClientModulein 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.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.