Ch. 4 · Angular

Angular Pure and Impure Pipes

Understand why pure pipes run only when inputs change, what makes a pipe impure, and how to avoid the performance cost.

~3 min readintermediateupdated Oct 5, 2026

A pipe transforms a value for display. By default a pipe is pure: Angular calls transform only when the input reference changes. Marking it pure: false makes it impure, and Angular runs it on every change-detection cycle, which is powerful and easy to misuse.

Before you start

You should be comfortable with templates and change detection. This article explains pipe purity; it assumes you know how to declare a standalone pipe.

Step-by-step walkthrough

Step 1: Rely on purity and memoization

A pure pipe runs when its input changes by reference and its result is cached between runs. *ngFor with filter on an array works because a new array reference triggers the pipe, and Angular skips it otherwise. This is why pure pipes are cheap and are the default.

Step 2: Know when a pipe becomes impure

A pipe is impure if you set pure: false or if it depends on mutable state such as Date.now() or a service property that changes without the input changing. An impure pipe runs on every cycle, so a filter over a large list re-runs on every keystroke anywhere in the app.

Step 3: Prefer derived state over impure pipes

When the transform depends on more than the input, compute it in the component with a signal or getter and pass the result in, so the work is tied to the real dependency. Reserve impure pipes for genuinely time-based or global-state displays, and keep them trivial.

Worked scenario

The pure pipe transforms only when the list reference changes.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'active', pure: true })
export class ActivePipe implements PipeTransform {
  transform(items: { active: boolean }[]): { active: boolean }[] {
    return items.filter((item) => item.active);
  }
}
TypeScript

Walk through the example

ActivePipe runs when a new array reference arrives and caches the filtered result otherwise. Replacing the array immutably triggers it correctly; mutating the array in place does not, because the reference is unchanged. That trade-off is why immutable updates pair with pure pipes.

Common mistake

Marking a pipe impure to make it notice a mutated array, which runs it on every cycle and hides the real problem, a mutation that should have produced a new reference. Another is putting an HTTP call or heavy computation in a pipe, which is a job for the component or a service.

Verify the behavior

Log inside transform and confirm a pure pipe runs only when the input reference changes. Switch the pipe to impure and count the calls during an unrelated keystroke; the count should jump on every cycle. Replace the in-place mutation with an immutable update and confirm the pure pipe runs again.

Interview exercise

A filter pipe misses updates after a push to the source array. Why, and what is the fix?

Answer and reasoning

A pure pipe compares by reference, and push mutates the existing array without changing its reference, so Angular sees no input change and skips transform. The fix is to produce a new array, for example with the spread operator, so the reference changes; making the pipe impure would work but re-runs it on every cycle and hides the mutation.

Continue learning

Compare derived state in Angular signal derived values and OnPush and input identity. Read the Angular pipes guide and try the Angular interview questions.

More in Angular

read ✓Angular · mid

Angular Defer Blocks and Lazy Rendering

Load template regions on demand with @defer, choose a trigger, and use placeholders without delaying critical content.

~2 min readread →
read ✓Angular · hard

Angular Global Error Handling

Catch uncaught errors with a custom ErrorHandler, distinguish client from HTTP errors, and surface safe messages to users.

~2 min readread →
read ✓Angular · mid

Angular Host Directives and Composition

Attach behavior to elements with attribute directives, bind to the host with the host property, and compose directives with hostDirectives.

~2 min readread →
esc