Angular Data Handling: When to use `| async` and when to `.subscribe()` manually
Habibur Rahman

Habibur Rahman @devhabib

About: Senior Frontend Engineer (8+ yrs). Angular expert, React experience. Passionate about building high-quality, pixel-perfect UIs with HTML, CSS, & TypeScript. Currently exploring Next.js.

Location:
Sylhet, Bangladesh
Joined:
Jul 16, 2021

Angular Data Handling: When to use `| async` and when to `.subscribe()` manually

Publish Date: Nov 19 '25
1 2

 One of the most common questions I get is: "Should I use the Async Pipe or subscribe manually?"

The answer is: Use the Async Pipe whenever possible. Subscribe manually only when necessary.

Here is the breakdown of both approaches.

Approach 1: The Gold Standard (Async Pipe)

If you simply need to display data from an API on the screen, do not subscribe in your TypeScript file. Pass the stream directly to the template.

Why?

  • Automatic Cleanup: Angular handles the unsubscription.
  • Cleaner Code: No ngOnInit or ngOnDestroy needed.
  • OnPush Compatible: Works great with performance optimizations.
<div *ngIf="data$ | async as data">
  {{ data.title }}
</div>
Enter fullscreen mode Exit fullscreen mode

Approach 2: The "Kill Switch" (Manual Subscription)

Sometimes, you can't use the pipe. Maybe you need to assign the data to a local variable to modify it, or send it to an analytics service.

In this case, you must manage the memory yourself. The safest way is the takeUntil pattern.

export class MyComponent implements OnDestroy {
  // 1. The Signal: Create a Subject to act as the "killer"
  private destroy$ = new Subject<void>(); 

  constructor(private dataService: DataService) {}

  ngOnInit(): void {
    this.dataService.getData()
      // 2. The Guard: Keep stream alive UNTIL destroy$ emits
      .pipe(takeUntil(this.destroy$)) 
      .subscribe(response => {
        this.data = response;
        // Logic happens here (e.g. calculations, logging)
        this.calculateTotals(response);
      });
  }

  ngOnDestroy(): void {
    // 3. The Trigger: Signal the subject to complete
    this.destroy$.next(); 
    this.destroy$.complete();
  }
}
Enter fullscreen mode Exit fullscreen mode

Summary:

  • Displaying data? Async Pipe.
  • Processing logic? Manual Subscription + takeUntil.

Don't mix them up, and your app will run smooth as butter.

Comments 2 total

Add comment