Releases & Deployment

A release bundles the ERTS (runtime), your compiled code and dependencies — no Elixir install needed on the server.

44.1 Mix releases

A release bundles the ERTS (runtime), your compiled code and dependencies — no Elixir install needed on the server.

Files: rel/env.sh.eex, rel/vm.args.eex, config/runtime.exs.

MIX_ENV=prod mix release
_build/prod/rel/my_app/bin/my_app start      # foreground
_build/prod/rel/my_app/bin/my_app daemon     # background
_build/prod/rel/my_app/bin/my_app remote     # attach a remote IEx
_build/prod/rel/my_app/bin/my_app eval "MyApp.Release.migrate()"
_build/prod/rel/my_app/bin/my_app stop
def project do
  [releases: [my_app: [include_executables_for: [:unix], applications: [runtime_tools: :permanent], steps: [:assemble, :tar]]]]
end

44.2 Docker

Phoenix generates one with mix phx.gen.release --docker.

FROM hexpm/elixir:1.18.1-erlang-27.2-debian-bookworm-20250101-slim AS build
WORKDIR /app
ENV MIX_ENV=prod
RUN mix local.hex --force && mix local.rebar --force
COPY mix.exs mix.lock ./
RUN mix deps.get --only prod && mix deps.compile
COPY . .
RUN mix compile && mix release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y libstdc++6 openssl libncurses6 locales && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/_build/prod/rel/my_app ./
CMD ["bin/my_app", "start"]

44.3 Platforms

Fly.io (first-class clustering), Gigalixir, Render, Heroku, Kubernetes (+ libcluster), bare metal/VMs (+ systemd).

44.4 Hot code upgrades

The BEAM can load new module versions without stopping (two versions coexist: current & old). Full release upgrades use appup/relup files (via tools like castle or distillery-style tooling). Most teams prefer rolling/blue-green deploys, but hot upgrades are available for systems that must never stop. In development, recompile() and Phoenix code reloading use the same mechanism.

🧪 Part III Exercises

Implement a key-value store as a raw process (spawn/receive), then as an Agent, then as a GenServer.

Build a rate limiter GenServer (N requests per second per user) backed by ETS.

Write a supervision tree where a Cache crashes randomly; observe restarts in :observer.

Create a chat room system using DynamicSupervisor + Registry (one process per room).

Use Task.async_stream to fetch 100 URLs concurrently with max concurrency 10 and timeouts.

Write a defenum macro that generates functions for an enum: defenum Color, [:red, :green].

Write a memoize macro that caches function results in ETS.

Connect two nodes and implement distributed ping-pong using :global names.

Build a GenStage pipeline: producer of numbers → filter stage → consumer that sums.

Build a release, run it as a daemon, attach with remote, and inspect state with :sys.get_state.