DEV Community

Cover image for 🧩 Providers vs ViewProviders in Angular — The Untold Difference
ROHIT SINGH
ROHIT SINGH

Posted on

🧩 Providers vs ViewProviders in Angular — The Untold Difference

If you’ve been working with Angular for a while, you’ve likely seen this in component metadata:

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  providers: [MyService],
  // or
  viewProviders: [MyService]
})
Enter fullscreen mode Exit fullscreen mode

At first glance, both providers and viewProviders seem identical.
They both inject services into a component, right?
So why did Angular create two separate options?

The difference lies in scope, encapsulation, and how Angular renders views and projected content.

Let’s take a deep dive into how these two work, why they exist, and how to choose the right one in your project.

🧠 Quick Refresher: How Dependency Injection Works in Angular

Angular’s Dependency Injection (DI) is like a smart factory that creates and shares services across your app.
Instead of manually creating new instances like:

const userService = new UserService();
Enter fullscreen mode Exit fullscreen mode

you simply ask Angular to give you one:

constructor(private userService: UserService) {}
Enter fullscreen mode Exit fullscreen mode

Angular then looks through a hierarchical injector tree to find (or create) that service instance.
Where you register that service (root, module, component) decides how many instances exist and who can use them.

🏗️ What Are Providers?

A provider is a set of instructions that tells Angular’s DI system how to obtain a value for a dependency token — usually a class, object, or value.

You can define providers at multiple levels:

root (global singleton)

NgModule (shared within a module)

Component (scoped to the component and its child tree)

Example:

@Component({
  selector: 'app-parent',
  template: `<app-child></app-child>`,
  providers: [MyService]
})
export class ParentComponent {
  constructor(private myService: MyService) {
    console.log('Parent service instance:', myService);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here’s what happens:

Angular creates a new instance of MyService specifically for ParentComponent.

All child components inside its view (like ) get the same instance.

But components outside of this parent do not share it.

It’s a perfect way to create isolated service instances for different UI sections — for example, different tabs or widgets on a page.

👁️ Enter ViewProviders — The Hidden Twin

Now, let’s talk about the lesser-known twin: viewProviders.

They do the same thing — provide services — but only for the component’s view hierarchy, not for its projected content (i.e., ).

In simpler terms:

viewProviders = “my component and its template children only”
providers = “my component, my template children, and any projected content”

Let’s look at an example to see this difference in action.

🧩 Example: The Real Difference

@Injectable()
export class LoggerService {
  log(message: string) {
    console.log(`Logger says: ${message}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, imagine we have a parent and child component:

@Component({
  selector: 'child-comp',
  template: `<p>Child Component Loaded</p>`
})
export class ChildComponent {
  constructor(private logger: LoggerService) {
    this.logger.log('Child Component using LoggerService');
  }
}
Enter fullscreen mode Exit fullscreen mode
@Component({
  selector: 'app-parent',
  template: `
    <child-comp>
      <p>Projected Content Here</p>
    </child-comp>
  `,
  viewProviders: [LoggerService]
})
export class ParentComponent {
  constructor(private logger: LoggerService) {
    this.logger.log('Parent Component using LoggerService');
  }
}
Enter fullscreen mode Exit fullscreen mode

Here’s what happens:

Both ParentComponent and ChildComponent can inject LoggerService.

But if the projected content (

Projected Content Here

) tried to inject it — it won’t work because viewProviders don’t expose services to projected content.

If you replace viewProviders with providers, then the projected content would also have access to LoggerService.

⚖️ providers vs viewProviders — Head-to-Head Comparison

💡 When Should You Use Each?
✅ Use providers When:

You’re building a parent component that exposes a service to its children and content.
(e.g., TabsComponent sharing state with TabContent)

You want shared state between component and content projected via .

Your service handles communication or coordination between parent and projected components.

✅ Use viewProviders When:

You want to encapsulate internal behavior (e.g., a form field’s internal logic).

You don’t want the projected content to accidentally inject or modify internal services.

You’re building UI libraries where isolation and clean boundaries are critical.

🧠 Pro Tip: Why Angular Created ViewProviders

When Angular introduced viewProviders, the goal was encapsulation.
Imagine you’re building a custom InputComponent that uses an internal ControlService to manage focus and validation.

If someone projects custom content into that input (say, or ), you don’t want them to accidentally inject your ControlService and modify internal behavior.

That’s exactly where viewProviders shine — they make sure your internal DI context stays private to your view.

🧭 Summary

Understanding the difference between providers and viewProviders can save you hours of debugging, especially in large apps or library code.

providers → Used when the service should be visible to everything — view + content.

viewProviders → Used when the service should stay internal — view only.

Think of it like:

🔓 providers → “Shared access”
🔒 viewProviders → “Private access”

🚀 Final Thoughts

Angular’s dependency injection isn’t just a feature — it’s a design philosophy.
By using viewProviders, you make your components more modular, encapsulated, and reusable — especially in large enterprise applications or shared UI libraries.

So next time you’re creating a new component, ask yourself:

“Should this service be visible outside my view?”

That simple question will help you choose between providers and viewProviders — and write cleaner, more maintainable Angular code. 💪

✨ Bonus Tip:

If you’re building Angular libraries or design systems, prefer viewProviders for internal logic.
It prevents service leaks and ensures that each component behaves independently, no matter where it’s used.

🚀 Rohit Singh 🚀 – Medium

Read writing from 🚀 Rohit Singh 🚀 on Medium. Full-stack developer with 6+ years in Angular, Node.js & AWS. Sharing tips, best practices & real-world lessons from building scalable apps.

favicon medium.com

Top comments (0)