0Pricing
Elixir & Phoenix: Scalable Backend Development · Lesson

Transactions and Ecto.Multi

Group multiple database operations into atomic units using Repo transactions and the composable Ecto.Multi struct.

Transactions and Ecto.Multi is a free Elixir & Phoenix: Scalable Backend Development lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Elixir & Phoenix: Scalable Backend Development learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Transactions?

A transaction bundles several operations so they all succeed or all roll back together, keeping data consistent.

Repo.transaction with a Function

The simplest form runs a function; if it returns normally the transaction commits, if it raises it rolls back.

Repo.transaction(fn ->
  Repo.insert!(%Account{balance: 100})
  Repo.insert!(%Log{action: "created"})
end)

Manual Rollback

Inside the function you can abort explicitly with Repo.rollback/1, which returns {:error, reason}.

Repo.transaction(fn ->
  case withdraw(account, 50) do
    {:ok, acc} -> acc
    {:error, r} -> Repo.rollback(r)
  end
end)

The Problem with Nested Functions

Function-based transactions get hard to read and reuse when steps depend on earlier results. Ecto.Multi solves this declaratively.

Building an Ecto.Multi

Ecto.Multi is a struct that accumulates named operations without touching the database until run.

alias Ecto.Multi
multi =
  Multi.new()
  |> Multi.insert(:user, %User{name: "Ada"})

Chaining Operations

Each operation gets a unique name, letting you reference earlier results and inspect them later.

Multi.new()
|> Multi.insert(:user, user_changeset)
|> Multi.insert(:profile, profile_changeset)

Depending on Earlier Steps

Pass a function to use the results of previous steps. It receives the repo and a map of completed operations.

Multi.new()
|> Multi.insert(:user, user_changeset)
|> Multi.run(:welcome, fn _repo, %{user: user} ->
  send_welcome(user)
end)

Running the Multi

Repo.transaction/1 executes the whole Multi atomically and returns {:ok, results} or an error tuple.

case Repo.transaction(multi) do
  {:ok, %{user: user}} -> {:ok, user}
  {:error, step, reason, _} -> {:error, step, reason}
end

Pinpointing Failures

On failure the error tuple names exactly which step failed and gives the changes made so far (which were rolled back).

{:error, :profile, changeset, _changes_so_far}

Other Multi Operations

Multi supports update, delete, update_all, and delete_all, mirroring Repo functions.

Multi.new()
|> Multi.update(:acc, changeset)
|> Multi.delete_all(:logs, old_logs_query)

Composability Wins

Because a Multi is just data, you can build it in pieces across functions and append more steps before running it, improving testability.

def base_multi, do: Multi.new() |> Multi.insert(:user, cs)
# elsewhere
base_multi() |> Multi.insert(:audit, audit_cs) |> Repo.transaction()

Quick Check

Test your transaction knowledge.

Recap

You made database changes atomic:

  • Repo.transaction with a function commits or rolls back together
  • Repo.rollback aborts explicitly
  • Ecto.Multi composes named steps as data
  • Failures return the failing step name and roll back everything

Frequently asked questions

Is the “Transactions and Ecto.Multi” lesson free?

Yes — the full text of “Transactions and Ecto.Multi” is free to read here on the web, and the Elixir & Phoenix: Scalable Backend Development course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Elixir & Phoenix: Scalable Backend Development course, upgrade to CoddyKit PRO.

What will I learn in “Transactions and Ecto.Multi”?

Group multiple database operations into atomic units using Repo transactions and the composable Ecto.Multi struct. You practise Elixir & Phoenix: Scalable Backend Development with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Elixir & Phoenix: Scalable Backend Development?

No prior experience is required. Elixir & Phoenix: Scalable Backend Development on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Transactions and Ecto.Multi” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Elixir & Phoenix: Scalable Backend Development lesson?

Yes. Every Elixir & Phoenix: Scalable Backend Development lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Ecto Schema and Database Migrations
  2. Repo, Changesets, and Queries
  3. Associations and Embedded Schemas
  4. Transactions and Ecto.Multi
← Back to Elixir & Phoenix: Scalable Backend Development