Services & Dependency Injection

@Injectable + inject() — One-Liner DI

Services & Dependency Injection

A service is a plain class with @Injectable. Components reach for it via the inject() function — no constructor wiring needed.

4 min read Level 2/5 #angular#services#di
What you'll learn
  • Decorate a service with @Injectable
  • Inject it with the inject() function
  • Compare inject() to constructor injection

Angular’s dependency injection is one of its oldest superpowers. A service is just a class — the framework constructs it on demand and hands the same instance to every consumer.

Define a service

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

export interface User { id: string; name: string }

@Injectable({ providedIn: 'root' })
export class UsersService {
  private http = inject(HttpClient);

  list() {
    return this.http.get<User[]>('/api/users');
  }
}

providedIn: 'root' makes it an application-wide singleton — and tree-shakable. If nothing injects it, the bundler can drop it entirely.

Inject from a component

import { Component, inject } from '@angular/core';
import { UsersService } from './users.service';

@Component({
  selector: 'app-users',
  standalone: true,
  template: `<p>{{ users().length }} users</p>`,
})
export class UsersComponent {
  private users$ = inject(UsersService).list();
  users = toSignal(this.users$, { initialValue: [] });
}

Constructor vs inject()

The old constructor form still works:

constructor(private users: UsersService) {}

But inject() is preferred because it works anywhere inside an injection context — field initializers, factory functions, route guards, resolvers, interceptors. No constructor required.

Injection Tokens →