The Async Pipe

Auto-Subscribe in the Template

The Async Pipe

The async pipe subscribes to an Observable or Promise in the template and unsubscribes automatically when the component is destroyed.

3 min read Level 1/5 #angular#rxjs#async
What you'll learn
  • Render Observable values with the async pipe
  • Combine it with @if and @for control flow
  • Bind the unwrapped value to a local name

async is the simplest way to display an Observable in a template. It subscribes when the view renders, pushes new values into the binding, and unsubscribes automatically — no manual cleanup.

Basic usage

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

@Component({
  selector: 'app-users',
  standalone: true,
  imports: [AsyncPipe],
  template: `<p>{{ count$ | async }} users</p>`,
})
export class UsersComponent {
  count$ = inject(UsersService).count();
}

With control flow

The bind-to-variable form (as user) lets you reference the unwrapped value multiple times.

@if (user$ | async; as user) {
  <h1>{{ user.name }}</h1>
  <p>{{ user.email }}</p>
} @else {
  <p>Loading...</p>
}

@for (item of items$ | async; track item.id) {
  <li>{{ item.label }}</li>
}

Why it matters

Every async is one less manual subscription you can forget to clean up. It also plays nicely with OnPush change detection — the pipe marks the view dirty only when a new value arrives.

Or use a signal

In modern Angular, toSignal is often nicer because the result is just a value you can use in expressions without piping:

import { toSignal } from '@angular/core/rxjs-interop';

user = toSignal(this.users.getCurrent());
<h1>{{ user()?.name }}</h1>

Both styles work — pick whichever feels clearer for the component at hand.

computed() & effect() →