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?
2. What is the performance risk of impure pipes?
3. What is the recommended alternative to impure pipes for filtering?
Flashcards
Question
When does a pure pipe re-evaluate?
Click to reveal answer
Answer
Only when the input reference changes or a primitive value changes. Results are cached.
Question
What is the risk of impure pipes?
Click to reveal answer
Answer
They run on every change detection cycle, causing performance issues with large lists.
Question
What is the best alternative to impure pipes?
Click to reveal answer
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()))
);