Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To create a custom pipe in Angular, write a TypeScript class decorated with @Pipe, give it a name, implement a transform method, and make the class available to the template that uses it. In a standalone component you add the pipe to the component’s imports array. In an NgModule-based project you list it in the module’s declarations. The name you set in @Pipe is what follows the | character in a template expression.

The shape of a custom pipe

Every custom pipe has the same four parts. Once you can name them, the rest of the process is repetition.

  • A decorated class. The @Pipe decorator from @angular/core marks the class as a pipe and holds its metadata.
  • A pipe name. The name property is the identifier used after | in a template, such as {{ word | reverse }}.
  • A transform method. This method contains the transformation. Angular calls it with the bound value as the first argument.
  • Registration in the consuming context. The template’s component must be able to see the pipe, either through its standalone imports or through an NgModule’s declarations.

The class is expected to implement the PipeTransform interface, which defines the shape of transform. Angular’s PipeTransform API reference describes the signature as transform(value, ...args): the bound value comes first, and any optional parameters follow it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I create a custom pipe in Angular?

The steps below build a pipe called reverse that flips a string. The Angular tutorial’s create a pipe lesson uses a similar exercise and a class named StarPipe; the names here are only examples.

  1. Generate or create the file. Create reverse.pipe.ts in the folder of the component that will use it. If you use the Angular CLI, ng generate pipe reverse creates a file and class with the same structure.
  2. Import the decorator and the interface. Add import { Pipe, PipeTransform } from '@angular/core'; at the top of the file.
  3. Declare the class with a name. Use @Pipe({ name: 'reverse' }). Pick a lowerCamelCase name that describes the task, because it is what appears in templates.
  4. Write transform with explicit types. Keep the input and output types clear so the template and the code agree about what goes in and what comes out.
  5. Register the pipe in the consuming component or module, as described in the next section.
  6. Use it in the template with {{ word | reverse }}.
import { Pipe, PipeTransform } from '@angular/core';
import { reverseText } from './text-utils';

@Pipe({
  name: 'reverse',
})
export class ReversePipe implements PipeTransform {
  transform(value: string): string {
    return reverseText(value);
  }
}

The pipe delegates the actual work to reverseText, which is defined in a separate file. That separation is covered in the section on reusing the logic outside templates.

How do I use a custom pipe in a component?

How you make a pipe available depends on how the project is organized. Angular’s current documentation supports standalone pipes imported by components, and it also documents NgModule declarations for module-based code. Both are valid, but they are not interchangeable in the same place.

Project setup Where the pipe is registered What the consuming code looks like
Standalone components The imports array of each component whose template uses the pipe imports: [ReversePipe] in the component’s @Component metadata
NgModule-based The declarations array of the NgModule that declares the consuming component declarations: [ReversePipe, GreetingComponent] in the module

Standalone component example

Import the pipe class into the component that uses it. The template can then reference the pipe by name.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { Component } from '@angular/core';
import { ReversePipe } from './reverse.pipe';

@Component({
  selector: 'app-greeting',
  imports: [ReversePipe],
  template: '<p>{{ word | reverse }}</p>',
})
export class GreetingComponent {
  word = 'Angular';
}

Pipes are not injected into a component in the way services are. The component’s imports array tells Angular which pipes its template may use.

NgModule-based example

In a module-based project, the pipe is listed in the declarations of the NgModule that declares the component using it. A standalone pipe is imported rather than listed in declarations, so keep the two approaches separate within a single project.

import { NgModule } from '@angular/core';
import { ReversePipe } from './reverse.pipe';
import { GreetingComponent } from './greeting.component';

@NgModule({
  declarations: [ReversePipe, GreetingComponent],
})
export class GreetingModule {}

If Angular reports that it cannot find a pipe in a template, check first that the pipe is listed in the consuming component’s imports or in the declarations of the module that declares that component. A pipe that exists in a file but is not registered in the right place produces this symptom.

How do I pass arguments to an Angular pipe?

Pipe parameters are added after the pipe name, separated by colons. Angular passes the value on the left of | as the first argument to transform, then each colon-separated value in order. The method parameters must line up with that order.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncate',
})
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit = 10, ellipsis = '…'): string {
    return value.length > limit ? value.slice(0, limit) + ellipsis : value;
  }
}
<p>{{ title | truncate:20:'...' }}</p>
<p>{{ title | truncate }}</p>
Template expression Value passed to value limit ellipsis
title | truncate:20:'...' The value of title 20 (from the first colon argument) '...' (from the second colon argument)
title | truncate The value of title 10 (default) '…' (default)

Give defaults to optional parameters, as shown, so that the pipe still works when a template omits them. Arguments are positional: you cannot skip the first one and pass only the second without writing a value for it.

Purity and change detection

Pipes are pure by default. A pure pipe runs its transform method only when its primitive input changes or when an object reference changes. Angular does not look inside arrays or objects to detect in-place edits. That is why a pure pipe that receives an array will not update when code pushes a new item into the same array.

// Not detected by a pure pipe: the array reference stays the same
this.items.push(newItem);

// Detected: a new array reference is created
this.items = [...this.items, newItem];

The better fix is almost always to update data immutably, by creating a new array or object whenever the data changes. Making the pipe impure is the other option, and the Angular guide treats it with caution. Angular’s pipes guide includes this warning:

“IMPORTANT: Avoid creating impure pipes unless absolutely necessary, as they can incur a significant performance penalty if used without care.”

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An impure pipe is declared with pure: false in the @Pipe metadata:

@Pipe({
  name: 'latest',
  pure: false,
})
export class LatestPipe implements PipeTransform {
  // runs on every change-detection cycle
}

The guide describes the penalty as qualitative, not as a measured number. An impure pipe runs on every change-detection cycle, so its cost grows with how often Angular checks the view and how expensive the transformation is. Use it only when internal state or in-place mutation genuinely has to be observed, and prefer immutable updates before reaching for it.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Reusing the transformation outside templates

Angular describes pipes as template operators rather than injectable services. A pipe class is designed to be used in templates, so the cleanest way to share its logic is to move the transformation into a standalone function. The pipe then calls that function, and any service or other code can import it directly.

// text-utils.ts
export function reverseText(value: string): string {
  return [...value].reverse().join('');
}

Angular’s guide puts the principle directly: “When you create a custom pipe, extract the transformation into a standalone function.” The same guide also notes that built-in formatting pipes have function equivalents in @angular/common. Functions such as formatDate, formatCurrency, formatNumber, and formatPercent can be called from code instead of injecting the matching pipe class.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The function approach keeps the template and non-template code consistent. If the rule changes, you update one function.

Checklist before you ship a custom pipe

  • The class is decorated with @Pipe and has a unique name.
  • The class implements PipeTransform and transform has typed input and output.
  • The pipe is imported into the standalone component’s imports, or declared in the correct NgModule.
  • Optional parameters have defaults and match the order used in the template.
  • The pipe is pure unless you have confirmed that the data cannot be updated immutably.
  • Logic that other code needs is in a standalone function, not only inside the pipe class.

“

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.