DEV Community

Adolfo Neto
Adolfo Neto

Posted on

The Elixir Pipe Operator

The Elixir pipe operator (|>) is beautiful.

How do you use it? Imagine you have a data structure and two or more functions that transform it in sequence.

Suppose you have a Numbers module in a file called numbers.ex:

defmodule Numbers do

  def filter_even_numbers(list) do
    Enum.filter(list, fn x -> rem(x, 2) == 0 end)
  end

  def double(list) do
    Enum.map(list, fn x -> x * 2 end)
  end

end
Enter fullscreen mode Exit fullscreen mode

Then, open an Interactive Elixir session:

$ iex numbers.ex
Enter fullscreen mode Exit fullscreen mode

Now, if you copy and paste this into your iex session:

iex> [1, 2, 3, 4, 5, 6]
|> Numbers.filter_even_numbers()
|> Numbers.double()
Enter fullscreen mode Exit fullscreen mode

You’ll get:

[4, 8, 12]
Enter fullscreen mode Exit fullscreen mode

Some say the pipe operator came from F#. I once asked José Valim, and he said he doesn't remember exactly where the idea came from. But it’s true that F# had pipe operators—more than one kind—before Elixir.

Want to go deeper into the pipe operator? Check out this excellent blog post by João Paulo Abreu: Learning Elixir: Pipe Operator. Don’t miss the “Further Reading” section.

And if you're looking for a course on functional programming, check the post below:

My "Introduction to Functional Programming" course will be fully remote.
Classes are expected to begin in early August.
Mondays, 15h50-18h40 (UTC-3).

Interested in joining? Please fill out the form to express your interest. You will be notified when enrollment opens.

bit.ly/IFP_2025

[image or embed]

— Adolfo Neto (@adolfont.github.io) June 13, 2025 at 8:49 AM

Top comments (1)

Collapse
 
muzhawir profile image
Muzhawir Amri

This is one of my favorite features in Elixir 🧙.

Without the pipe operator we have to compose functions using a staircasing style, which forces us to read code from the inside out:

to_string(abs(div(-100, 4)))
Enter fullscreen mode Exit fullscreen mode

Now imagine chaining more than ten functions like that, it quickly becomes hard to read.

With pipe operator we can rewrite the same logic in a more readable left-to-right flow:

-100 |> div(4) |> abs() |> to_string()
Enter fullscreen mode Exit fullscreen mode

Or using a multi-line format:

-100
|> div(4)
|> abs()
|> to_string()
Enter fullscreen mode Exit fullscreen mode