Pure Pipe vs Impure Pipe in Angular
1. What is a Pure Pipe?
A pure pipe executes when Angular detects a change in:
- A primitive input value such as
string,number, orboolean, or - The reference of an object, array, date, etc.
By default, Angular custom pipes are pure.
@Pipe({
name: 'myPipe',
pure: true
})
pure: true is the default, so normally you don't need to specify it.
2. What is an Impure Pipe?
An impure pipe can execute during Angular's change-detection cycles even when the input object's reference has not changed.
It is declared using:
@Pipe({
name: 'myPipe',
pure: false
})
This allows the pipe to react to internal mutations of objects and arrays, but it can have a significant performance cost.
3. Why Do We Need Pure and Impure Pipes?
Consider an array:
users = ['Syed', 'John'];
Suppose we modify the existing array:
this.users.push('David');
The array's contents changed, but the array reference remains the same.
Conceptually:
Before
users ──────► Array A
Syed
John
After push()
users ──────► Array A
Syed
John
David
Reference = Same
Contents = Changed
A pure pipe doesn't re-run merely because the contents of the same array/object were mutated.
An impure pipe can re-run during change detection and therefore see that mutation.
4. Full Simple Sample Program
Let's create a pipe that displays names as a comma-separated string.
names-pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'names'
})
export class NamesPipe implements PipeTransform {
transform(value: string[]): string {
console.log('Pure pipe executed');
return value.join(', ');
}
}
This is a pure pipe because pure: true is the default.
app.ts
import { Component } from '@angular/core';
import { NamesPipe } from './names-pipe';
@Component({
selector: 'app-root',
imports: [
NamesPipe
],
templateUrl: './app.html'
})
export class App {
users = ['Syed', 'John'];
addUser() {
this.users.push('David');
}
replaceUsers() {
this.users = [...this.users, 'David'];
}
}
app.html
<h2>Pure Pipe Example</h2>
<p>{{ users | names }}</p>
<button (click)="addUser()">
Add User using push()
</button>
<br><br>
<button (click)="replaceUsers()">
Add User using new array
</button>
Initially:
Syed, John
5. Pure Pipe Behavior
When we execute:
this.users.push('David');
we are changing the existing array.
Array reference
↓
SAME
Because the reference hasn't changed, the pure pipe doesn't re-run solely because of that mutation.
But when we do:
this.users = [...this.users, 'David'];
we create a new array.
Old Array
↓
Syed, John
New Array
↓
Syed, John, David
The reference changed:
Old Reference
↓
New Reference
Therefore, Angular executes the pure pipe again.
This immutable approach is generally preferred.
6. Creating an Impure Pipe
Now change the pipe to:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'names',
pure: false
})
export class NamesPipe implements PipeTransform {
transform(value: string[]): string {
console.log('Impure pipe executed');
return value.join(', ');
}
}
The important difference is:
pure: false
Now:
this.users.push('David');
can be reflected because the impure pipe executes during change detection even though the array reference remains unchanged.
7. Pure vs Impure Pipe
| Feature | Pure Pipe | Impure Pipe |
|---|---|---|
| Default | Yes | No |
| Configuration | pure: true |
pure: false |
| Primitive value change | Executes | Executes |
| Object reference change | Executes | Executes |
| Internal object mutation | Doesn't re-run merely for mutation | Can detect it during change detection |
Array push() |
Doesn't trigger pipe by itself | Can reflect change |
| New array reference | Executes | Executes |
| Execution frequency | Lower | Potentially very frequent |
| Performance | Better | Can be expensive |
| Recommended | Yes | Only when necessary |
8. Important Example: push() vs New Array
This distinction is very important for interviews.
Mutation
this.users.push('David');
Reference remains:
Same
A pure pipe may not execute again.
Immutable update
this.users = [...this.users, 'David'];
Reference becomes:
New
The pure pipe executes again.
So instead of relying on an impure pipe, prefer immutable updates when practical:
this.users = [...this.users, newUser];
9. Advantages of Pure Pipes
Better performance
Angular doesn't need to execute the transformation on every change-detection pass.
Predictable behavior
The output depends on the input value/reference.
Suitable for most transformations
For example:
Formatting
Filtering immutable data
Text transformation
Calculations
Default Angular behavior
You don't need:
pure: true
Explicitly.
10. Disadvantages of Pure Pipes
A pure pipe won't automatically react to an internal mutation such as:
this.users.push('David');
if the array reference remains unchanged.
Instead, prefer:
this.users = [...this.users, 'David'];
11. Advantages of Impure Pipes
Impure pipes can respond when an existing object's or array's internal data changes.
For example:
this.users.push('David');
without replacing the array reference.
They can be useful in specific scenarios involving mutable data.
12. Disadvantages of Impure Pipes
The biggest concern is performance.
An impure pipe may execute very frequently during change detection.
Imagine:
<p>{{ users | names }}</p>
If Angular performs change detection repeatedly:
Change Detection
↓
Impure Pipe
↓
transform()
Change Detection
↓
Impure Pipe
↓
transform()
Change Detection
↓
Impure Pipe
↓
transform()
If transform() performs expensive filtering, sorting, or calculations, application performance can suffer.
Therefore:
Prefer pure pipes. Use impure pipes only when there is a clear requirement.
13. Key Points
- Angular pipes are pure by default.
- Pure pipe:
pure: true
- Impure pipe:
pure: false
- Pure pipes execute when primitive values change or object/array references change.
- Pure pipes don't re-run merely because an existing object's internal state was mutated.
- Impure pipes can execute during change detection regardless of whether the reference changed.
- Impure pipes can therefore detect mutations such as:
array.push()
- Impure pipes can cause performance problems if their transformation is expensive.
- Prefer immutable updates:
this.users = [...this.users, newUser];
rather than using an impure pipe merely to handle:
this.users.push(newUser);
14. Interview Questions and Answers
Q1. What is the difference between pure and impure pipes?
A pure pipe executes when its input value or object reference changes.
An impure pipe can execute during every Angular change-detection cycle, allowing it to react to internal object or array mutations.
Q2. Are Angular pipes pure by default?
Yes.
@Pipe({
name: 'myPipe'
})
is effectively:
@Pipe({
name: 'myPipe',
pure: true
})
Q3. How do you create an impure pipe?
Set:
pure: false
Example:
@Pipe({
name: 'myPipe',
pure: false
})
Q4. Why are pure pipes faster?
Because Angular can avoid executing them when their input values/references haven't changed.
Q5. Why should we be careful with impure pipes?
Because they may execute frequently during change detection.
If the transformation is expensive, this can negatively affect application performance.
Q6. Will a pure pipe detect array.push()?
Not merely because of the push() operation.
this.users.push('David');
mutates the existing array while keeping the same reference.
Instead, create a new array:
this.users = [...this.users, 'David'];
The new reference causes the pure pipe to execute.
Q7. Which should we use in real applications?
Prefer pure pipes for most scenarios.
Use impure pipes only when you specifically need to react to mutable data and understand the change-detection/performance implications.
Interview One-Line Answer
A pure pipe runs when its input value or reference changes, while an impure pipe can run during every change-detection cycle and can therefore detect internal mutations, but with a potentially higher performance cost.