Elixir Cheatsheet

Mix, Testing, and Tooling

Use this Elixir reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Mix Project Commands

mix new demo               # library/app skeleton (--sup for a supervision tree)
mix compile
mix test
mix format
mix deps.get
mix deps.update package_name
mix hex.info package_name
mix run -e 'IO.puts(Demo.hello())'
mix xref graph --label compile-connected   # find compile-time dependencies

Mix is the build tool: it compiles code, manages dependencies, runs tests, formats files, and hosts custom tasks (lib/mix/tasks/*.ex).

mix.exs Essentials

def project do
  [
    app: :demo,
    version: "0.1.0",
    elixir: "~> 1.18",
    deps: deps()
  ]
end

def application do
  [extra_applications: [:logger], mod: {Demo.Application, []}]
end

defp deps do
  [
    {:jason, "~> 1.4"},
    {:req, "~> 0.5"},
    {:credo, "~> 1.7", only: [:dev, :test], runtime: false}
  ]
end

elixir: "~> 1.18" is a minimum requirement, not a pin. mix.lock records resolved dependency versions — commit it for applications.

ExUnit Basics

# test/demo_test.exs
defmodule DemoTest do
  use ExUnit.Case, async: true

  test "adds numbers" do
    assert Demo.add(2, 3) == 5
  end
end

Use async: true for tests that do not share global state, databases, files, or named processes. test/test_helper.exs runs first and calls ExUnit.start().

describe, setup, and Tags

defmodule AccountsTest do
  use ExUnit.Case, async: true

  setup_all do
    {:ok, conn: connect()}          # once per module; merged into context
  end

  setup context do
    user = create_user()
    on_exit(fn -> cleanup(user) end)
    {:ok, user: user}               # before every test
  end

  describe "create_user/1" do
    test "with valid attrs", %{user: user, conn: conn} do
      assert user.id
    end

    @tag :slow
    test "bulk import" do
      # ...
    end
  end
end
mix test test/accounts_test.exs        # one file
mix test test/accounts_test.exs:42     # the test at line 42
mix test --only slow                   # only @tag :slow tests
mix test --exclude slow                # skip them (or ExUnit.configure(exclude: [:slow]))
mix test --failed                      # re-run last failures
mix test --stale                       # only tests affected by changed code

Assertions

assert value == 3
refute Enum.empty?(items)
assert {:ok, user} = Accounts.create_user(attrs)     # pattern-match assertion
assert_raise ArgumentError, fn -> bad_call() end
assert_receive {:done, _}, 500                        # message-passing tests
assert_in_delta 0.1 + 0.2, 0.3, 1.0e-9

Pattern matching inside assert is idiomatic for tagged results, and failures print a diff of the match.

Doctests

defmodule MathBox do
  @doc """
      iex> MathBox.double(4)
      8
  """
  def double(n), do: n * 2
end
defmodule MathBoxTest do
  use ExUnit.Case, async: true
  doctest MathBox
end

Doctests keep examples executable. Use them for small deterministic functions, not complex setup.

Formatting, Credo, Dialyzer

mix format                    # standard formatter (config: .formatter.exs)
mix format --check-formatted  # CI check
mix credo --strict            # style/design lints
mix dialyzer                  # success typing (dep: dialyxir)
mix test --cover              # coverage report

IEx Debugging

dbg(value)              # prints code + value; pipes show each step
IO.inspect(value, label: "value")
require IEx; IEx.pry()  # breakpoint (run under iex -S mix)
iex -S mix              # project shell; recompile with `recompile`
iex -S mix test         # pry inside tests needs --trace or a timeout bump
h Enum.map              # docs in IEx; i value — type info

Application Config

# config/config.exs — compile time
config :demo, feature_flags: [beta: true]

# config/runtime.exs — boot time, right place for env vars
config :demo, Demo.Repo, url: System.fetch_env!("DATABASE_URL")

# reading
Application.fetch_env!(:demo, :feature_flags)
Application.get_env(:demo, :missing, :default)

Runtime secrets come from environment variables or a secret manager via config/runtime.exs, never committed config files.