Skip to the solution
MediumFrontend9 min read

What is the difference between providing a service in root vs in a component?

288 views

The problem

Question presented to candidate: "We have a CartService. One teammate put providedIn: 'root' on it, another added it to a component's providers array, and now some screens see an empty cart. Explain the difference between those two ways of providing it."

What a strong answer should cover:

  • providedIn: 'root' registers the service in the root environment injector: one singleton for the whole app, created on first use, living until the app is destroyed.
  • providers: [CartService] on a component registers it in that component's element injector: a new instance per component instance, shared with that component's children, destroyed with it (its ngOnDestroy runs).
  • Lookup walks up from the requesting component, so a component-level provider shadows the root one for its subtree; that is why some screens saw a different, empty cart.
  • When to use each: root for app-wide state and stateless helpers; component-level for per-widget state that must reset when the widget goes away.
  • Root providers are tree-shakable by design (no providers array references the class), while a class listed in providers is always bundled.

Clarifying questions expected:

  • "Should every screen share one cart, or should each widget own its own state?"
  • "Is the component that provides it rendered more than once, for example in a list?"

Code / implementation expected: Yes β€” count instances created and destroyed under each option.

  • di
  • providedin

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read Β· 10 sections

Read the code

AngularCounting constructions: one root singleton vs one instance per component
import { Component, Injectable, OnDestroy, inject, signal } from "@angular/core";

let created = 0;

// One class, two ways to provide it.
@Injectable({ providedIn: "root" })
export class CartService implements OnDestroy {
  readonly id = ++created;
  readonly items = signal(0);
  constructor() { console.log(`CartService #${this.id} created`); }
  ngOnDestroy() { console.log(`CartService #${this.id} destroyed`); }
}

// No providers: asks the tree, finds the root singleton.
@Component({
  selector: "app-shared-cart",
  template: `<p>shared uses #{{ cart.id }} items={{ cart.items() }}
    <button (click)="cart.items.update(n => n + 1)">add</button></p>`,
})
export class SharedCart { cart = inject(CartService); }

// providers: [CartService] gives THIS component (and its children) a fresh instance.
@Component({
  selector: "app-own-cart",
  providers: [CartService],
  template: `<p>own uses #{{ cart.id }} items={{ cart.items() }}
    <button (click)="cart.items.update(n => n + 1)">add</button></p>`,
})
export class OwnCart { cart = inject(CartService); }

@Component({
  selector: "app-root",
  imports: [SharedCart, OwnCart],
  template: `
    <app-shared-cart />
    <app-shared-cart />
    @if (showOwn()) { <app-own-cart /> <app-own-cart /> }
    <button (click)="showOwn.set(!showOwn())">toggle own carts</button>
  `,
})
export class AppComponent {
  showOwn = signal(true);
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 72 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

What is the customElements schema in Angular and when do you need to use it?

Continue