# `dbg/2` shows every step of your pipeline

Debugging a pipeline usually means breaking it apart with `IO.inspect/2` calls between every stage, labelling each one so you can tell them apart, then deleting them all afterwards. Elixir has shipped a macro since 1.14 that does the whole thing with one call at the end of the pipe.

```elixir
%{"tags" => "elixir, phoenix ,beam"}
|> Map.fetch!("tags")
|> String.split(",")
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
|> dbg()
```

That prints every stage with its intermediate value:

```
[tags.exs:6: (file)]
%{"tags" => "elixir, phoenix ,beam"} #=> %{"tags" => "elixir, phoenix ,beam"}
|> Map.fetch!("tags") #=> "elixir, phoenix ,beam"
|> String.split(",") #=> ["elixir", " phoenix ", "beam"]
|> Enum.map(&String.trim/1) #=> ["elixir", "phoenix", "beam"]
|> Enum.reject(&(&1 == "")) #=> ["elixir", "phoenix", "beam"]
```

`dbg/2` is a macro, not a function, so it can see the syntax of what it was piped into. It rewrites the pipeline to capture each step, prints the source of every stage next to its result, and returns the final value unchanged — dropping it into an existing pipe changes nothing about what the code does.

## Why the output beats `IO.inspect/2`

The labels come from the source, so they cannot drift out of sync the way a hand-written `label:` does. `String.split(",")` is shown as `String.split(",")`, not as `"after split"` that you wrote three refactors ago and which no longer describes the step. And because it is one call at the end rather than N calls interleaved, removing it is a single-line deletion — no risk of shipping a stray inspect that survived the cleanup.

## Bare `dbg()` dumps your bindings

Called with no arguments, it inspects `binding()` for you:

```elixir
base = 10
rate = base * 1.5
dbg()

# binding() #=> [base: 10, rate: 15.0]
```

## Truncating noisy values

The second argument takes `Inspect` options, so the usual controls still apply:

```elixir
1..100 |> Enum.map(&(&1 * 2)) |> dbg(limit: 5)

# 1..100 #=> 1..100
# |> Enum.map(&(&1 * 2)) #=> [2, 4, 6, 8, 10, ...]
```

One thing to know about scope: the pipeline breakdown is what you get in scripts, tests, and `mix run`. Inside `iex`, `dbg/2` is backed by `IEx.Pry` instead and can stop at the call to let you step through the pipeline interactively. Same call, different capability depending on where it runs.

[`Kernel.dbg/2` docs](https://hexdocs.pm/elixir/Kernel.html#dbg/2)


---

Created by: almirsarajcic
Date: August 28, 2026
URL: https://elixirdrops.net/d/DyiMo9nB
