# `tap/2` runs side effects in pipelines

Need to log, send a message, or cache a value mid-pipeline without breaking the flow? `tap/2` executes a function for its side effect, ignores the return value, and passes the original input through unchanged.

```elixir
order
|> calculate_total()
|> tap(&Logger.info("Order total: #{inspect(&1)}"))
|> tap(&send(self(), {:order_ready, &1}))
|> format_receipt()
```

Functions like `Logger.info/1` return `:ok` and `send/2` returns a pid—neither returns your data. Piping directly to them breaks the chain. `tap/2` lets you run these side effects while keeping your data flowing.

## Common use cases

```elixir
# Notify processes mid-pipeline
user
|> Accounts.update_profile(attrs)
|> tap(fn
  {:ok, user} -> send(self(), {:profile_updated, user.id})
  {:error, _} -> send(self(), :profile_update_failed)
end)
|> handle_result()

# Cache intermediate results
expensive_computation()
|> tap(&Cachex.put(:my_cache, "result", &1))
|> further_processing()

# Log at specific pipeline stages
request
|> parse_params()
|> tap(&Logger.info("Parsed: #{inspect(&1)}"))
|> validate()
|> tap(&Logger.info("Validated: #{inspect(&1)}"))
|> execute()
```

Any function you want to call for its side effect—not its return value—belongs in `tap/2`.


---

Created by: almirsarajcic
Date: December 17, 2025
URL: https://elixirdrops.net/d/vcnU82L4
