Skip to content
intermediate Phase 6 · Pipes and Component Styling

Pure vs Impure Pipes

Choose pipe purity carefully to avoid wasted recalculation.

35m
0 problems
Topic Progress 0%

Pure Pipes (Default)

Pure pipes are the default. Angular only re-evaluates a pure pipe when the input reference changes or a primitive value changes.

How Pure Pipes Work

@Pipe({
  name: 'pureExample',
  standalone: true,
  pure: true, // default — can be omitted
})
export class PureExamplePipe implements PipeTransform {
  transform(value: string): string {
    console.log('Pipe evaluated');
    return value.toUpperCase();
  }
}

Angular caches the result and only re-runs the pipe when:

  • The input reference changes (new object/array)
  • A primitive input value changes (string, number, boolean)

Pure Pipe with Object Input

@Pipe({
  name: 'userFullName',
  standalone: true,
})
export class UserFullNamePipe implements PipeTransform {
  transform(user: { firstName: string; lastName: string }): string {
    return `${user.firstName} ${user.lastName}`;
  }
}
<!-- Only re-evaluates when user reference changes -->
<p>{{ user | userFullName }}</p>

If you mutate user.firstName, the pipe will NOT re-run because the reference has not changed.

Performance Benefit

Pure pipes are cheap because they are cached:

<!-- This pipe runs once per input change, not per change detection cycle -->
<p *ngFor="let user of users">{{ user | userFullName }}</p>

Impure Pipes and When to Use Them

Impure pipes re-evaluate on every change detection cycle, regardless of whether the input changed. Use them sparingly.

Creating an Impure Pipe

@Pipe({
  name: 'filterBy',
  standalone: true,
  pure: false, // impure pipe
})
export class FilterByPipe implements PipeTransform {
  transform<T>(items: T[], property: keyof T, value: string): T[] {
    return items.filter(item =>
      String(item[property]).toLowerCase().includes(value.toLowerCase())
    );
  }
}
<input [(ngModel)]="searchText" placeholder="Search...">
<p *ngFor="let user of users | filterBy: 'name': searchText">
  {{ user.name }}
</p>

When to Use Impure Pipes

  • Filtering or sorting based on mutable state
  • When the input is an object that gets mutated in place
  • When the pipe depends on external state (e.g., current time)

Performance Warning

Impure pipes run on every change detection cycle:

<!-- This pipe runs on EVERY change detection, even if users hasn't changed -->
<p *ngFor="let user of users | filterBy: 'name': searchText">
  {{ user.name }}
</p>

For large lists, this can cause significant performance issues.

Better Alternative: Computed Signals

@Component({
  selector: 'app-user-list',
  template: `
    <input [(ngModel)]="searchText" placeholder="Search...">
    <p *ngFor="let user of filteredUsers()">{{ user.name }}</p>
  `,
})
export class UserListComponent {
  searchText = '';
  users = signal<User[]>([]);

  filteredUsers = computed(() => {
    const query = this.searchText().toLowerCase();
    return this.users().filter(u =>
      u.name.toLowerCase().includes(query)
    );
  });
}

The computed signal only recalculates when searchText or users changes — not on every change detection cycle.

Pure vs Impure Comparison

Feature Pure Impure
Default Yes No
Re-evaluates On input reference change Every change detection
Performance Fast (cached) Slow (runs constantly)
Use for Display transformations Filtering mutable state
Recommendation Preferred Avoid if possible

Quiz

1. When does a pure pipe re-evaluate?

Question 1 options

2. What is the performance risk of impure pipes?

Question 2 options

3. What is the recommended alternative to impure pipes for filtering?

Question 3 options

Flashcards

Question

When does a pure pipe re-evaluate?

Answer

Only when the input reference changes or a primitive value changes. Results are cached.

Question

What is the risk of impure pipes?

Answer

They run on every change detection cycle, causing performance issues with large lists.

Question

What is the best alternative to impure pipes?

Answer

Computed signals — only recalculate when dependencies change.

Revision Notes

Key Takeaways

  • 1. Pure pipes (default) cache results and only re-evaluate on input reference change
  • 2. Impure pipes run on every change detection cycle — performance risk
  • 3. Use computed signals instead of impure pipes for filtering
  • 4. Prefer pure pipes for all display transformations

Interview Tips

  • • Explain the caching behavior of pure pipes
  • • Be ready to describe when impure pipes are necessary
  • • Mention computed signals as the modern alternative

Cheat Sheet

Pure vs Impure Pipes Cheat Sheet

Pure (default):

@Pipe({ name: 'myPipe', standalone: true })
// Re-evaluates only on input reference change

Impure:

@Pipe({ name: 'myPipe', pure: false, standalone: true })
// Re-evaluates on every change detection — use sparingly

Best alternative:

filteredItems = computed(() =>
  this.items().filter(i => i.name.includes(this.search()))
);

Continue Learning