Elixir Cheat Sheet
Elixir syntax, pattern matching, pipe operators, and OTP concurrency primitives for building fault-tolerant BEAM applications.
Basic Syntax
Bindings, control flow, and printing.
age = 30name = "Ada"pi = 3.14159if age >= 18 do IO.puts("#{name} is an adult")endfor i <- 0..4 do IO.puts("Count: #{i}")end
Pattern Matching & Pipe Operator
Destructuring and composing transformations.
{status, message} = {:ok, "loaded"} # destructuring match[first | rest] = [1, 2, 3, 4] # head/tail matchIO.inspect(first) # 1IO.inspect(rest) # [2, 3, 4]nums = [5, 3, 1, 4, 2]result = nums |> Enum.filter(&(&1 > 2)) |> Enum.map(&(&1 * 2)) |> Enum.sum() # pipe: nums |> filter |> map |> sum
Processes & OTP
GenServer and lightweight process concurrency.
defmodule Counter do use GenServer def start_link(initial), do: GenServer.start_link(__MODULE__, initial) def init(state), do: {:ok, state} def handle_call(:get, _from, state), do: {:reply, state, state} def handle_call(:increment, _from, state), do: {:reply, state + 1, state + 1}end{:ok, pid} = Counter.start_link(0)GenServer.call(pid, :increment)GenServer.call(pid, :get) # 1
Core Keywords & Operators
Common Elixir language constructs.
- |>- pipe operator, passes left result as first arg to right function
- def / defp- public and private module function definitions
- case / cond- multi-branch pattern matching / condition dispatch
- %{}- map literal, e.g. %{name: "Ada"}
- GenServer- OTP behaviour for stateful server processes
- spawn / send / receive- lightweight process creation and message passing
- Enum / Stream- eager and lazy collection-processing modules
GenServer Boilerplate
A stateful server process with sync and async calls.
defmodule Counter do use GenServer # Client API def start_link(init), do: GenServer.start_link(__MODULE__, init, name: __MODULE__) def inc, do: GenServer.cast(__MODULE__, :inc) def value, do: GenServer.call(__MODULE__, :value) # Server callbacks @impl true def init(n), do: {:ok, n} @impl true def handle_cast(:inc, n), do: {:noreply, n + 1} @impl true def handle_call(:value, _from, n), do: {:reply, n, n}end
with for Happy-Path Chaining
Compose several ok/error tuples without nested case.
def create_user(params) do with {:ok, data} <- validate(params), {:ok, user} <- insert(data), {:ok, _mail} <- send_welcome(user) do {:ok, user} else {:error, :invalid} -> {:error, "bad input"} {:error, reason} -> {:error, reason} endend
Streams & Comprehensions
Lazy pipelines and multi-generator comprehensions.
# Lazy: nothing runs until Enum forces it1..1_000_000|> Stream.map(&(&1 * 2))|> Stream.filter(&(rem(&1, 3) == 0))|> Enum.take(5)# Comprehension with filter and intofor x <- 1..5, y <- 1..5, x + y == 6, into: %{} do {x, y}end#=> %{1 => 5, 2 => 4, 3 => 3, 4 => 2, 5 => 1}
Mix & Tooling
Everyday build, test, and dependency commands.
- mix new my_app --sup- scaffold a project with a supervision tree
- mix deps.get- fetch dependencies declared in mix.exs
- mix test --failed- rerun only tests that failed last time
- mix format- auto-format code per .formatter.exs
- iex -S mix- start an IEx shell with your project loaded
- mix dialyzer- run static type analysis (via dialyxir)
- mix release- build a self-contained production release
Let it crash: rely on OTP supervisors to restart failing processes instead of wrapping every operation in defensive try/rescue — Elixir's fault tolerance is designed around supervision trees.