Jesse Leite

February 28th, 2026

Pattern Match Made in Heaven

In most languages, = is merely an assignment operator. In Elixir, = is actually called the match operator, and it's one of the first things you'll learn in Elixir that might just completely rewire your brain!

Of course, we can still use = for basic assignment:

name = "Jesse"

But what's actually happening here is that Elixir is matching the left side against the right side, binding matched variables along the way.

This becomes powerful when you start matching against more complex data structures:

{:ok, value} = {:ok, 42}
# value is now 42

{:error, reason} = {:error, "not found"}
# reason is now "not found"

This is not unlike basic destructuring in PHP or JS:

const [status, value] = ["ok", 42];

Except in JS, a failed destructure silently gives you undefined, not to mention both PHP and JS are quite limiting when it comes to what you can do with destructuring.

Elixir's pattern matching is on a whole different level, because Elixir also asserts the shape.

For example, when using the = match operator, a failed match will blow up with a MatchError:

{:ok, value} = {:error, "not found"}
# ** (MatchError) no match of right hand side value: {:error, "not found"}

Or when pattern matching within case, cond, with, etc., you can branch on possible matches, which can make for some really elegant error handling:

case Http.get(url) do
  {:ok, %{status: 200, body: body}}
    -> Jason.decode!(body)

  {:ok, %{status: 403}}
    -> View.render(:forbidden)

  {:ok, %{status: 404}}
    -> View.render(:not_found)

  {:error, _}
    -> Logger.error("Response failure!")
end

This starts to get really crazy when you realize that you can pattern match nearly anywhere in Elixir!

For example, instead of handling branching logic via conditionals within a function's body, you can pattern match right in the definition itself:

defp response({:ok, %{status: 200, body: body}}) do
  Jason.decode!(body)
end

defp response({:ok, %{status: 404}}) do
  View.render(:not_found)
end

defp response({:error, _}) do
  Logger.error("Response failure!")
end

Elixir will then check each function clause in order until it finds a pattern match, to determine which clause to run.

Once you start thinking in patterns, it will fundamentally change how you handle data, errors, and control flow. Instead of writing defensive checks and nesting conditionals, you can often just describe the shape of the data you expect, and Elixir will do the rest ...How neat is that!?

Thanks for reading!

For updates, follow me on Twitter / X or subscribe via RSS.

Series: Elixir for PHP Devs

In Progress
  1. Introduction
  2. The Glorious Pipe Operator
  3. Pattern Match Made in Heaven
  4. eyes-emoji

email-icon-emoji feed-icon-emoji linkedin-icon-emoji github-icon-emoji x-icon-emoji

© Jesse Leite