Skip to main content
pipe and flow let you chain multiple functions together without nested calls or intermediate variables. Both are fully type-safe: each function’s return type determines the next function’s input type, and TypeScript errors early if the types don’t connect.

pipe — execute immediately

pipe(initialValue, fn1, fn2, fn3) passes initialValue through each function left-to-right and returns the final result:
Without pipe, the same code nests outward from the inside:

flow — create a reusable function

flow(fn1, fn2, fn3) returns a new function that accepts the first function’s input and returns the last function’s output. Nothing runs until you call the result:
Use pipe when you have the value now. Use flow when you want to define the transformation once and apply it to multiple values later — for example, as a map callback or a reusable utility.

Type safety

TypeScript checks each step in the pipeline. If the output type of one function doesn’t match the input type of the next, you get a compile-time error:

The built-in .pipe() on Result

Result<T, E> and ResultAsync<T, E> have a .pipe() method that threads the full Result through a sequence of functions. Unlike the standalone pipe, these functions receive the Result itself, not just the inner value:
This is useful for applying reusable Result transformations as a composable pipeline.
The .pipe() method on Result short-circuits on Err ; downstream functions still receive the Result and can choose to handle the error. It does not automatically skip errored steps the way .map() does. Build your pipeline functions to check .isOk() or use .map(), .andThen(), etc. internally.

Practical example

A data transformation pipeline that parses, validates, and formats an API payload: