This is a short introduction to creating releases with Elixir 1.9.1+ which contains built-in tooling for releases.

A release is a bundle of the runtime and pre-compiled code, and a set of configurations more suitible for production (like running in embedded mode).

On top of that, Elixir’s new built-in release handling adds some much needed tools for runtime configuration for releases, something that has been a pain in the past, with tools like relx.

Creating a Release

In 1.9.1+ creating a release is super easy. You can ask mix to generate some release configuration files for you:

$ mix release.init

and create a release with

$ mix release

which will generate a release in (by default)

 _build/dev/rel/<release>

To create a production release

MIX_ENV=prod mix release

which will output a release in

 _build/prod/rel/<release>

You can now tar the release folder and move it to your target system.

Running a Release

I’ve created an example project with mix new --sup and changed my application controller to:

defmodule ReleaseExample.Application do
  use Application

  def start(_type, _args) do
    IO.puts("Hello Release")
    opts = [strategy: :one_for_one, name: ReleaseExample.Supervisor]
    Supervisor.start_link([], opts)
  end
end

And created a dev release with mix release.

Now let’s try and start it:

$ _build/dev/rel/release_example/bin/release_example start
Hello Release

Great, it works.

You can also start it with an iex shell with

$ _build/dev/rel/release_example/bin/release_example start_iex
Erlang/OTP 22 [erts-10.4.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Hello Release
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(release_example@tbugsgnmbp)1>

but in a production system you are better of running the regular start command as a service (with systemd, in a container, or however you normally run services) and connect to it with a remote shell:

# shell 1
$ _build/dev/rel/release_example/bin/release_example start
Hello Release


# shell 2
$ _build/dev/rel/release_example/bin/release_example remote
Erlang/OTP 22 [erts-10.4.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(release_example@tbugsgnmbp)1>

Configuration

Configuration works like normal. config/config.exs is the compile-time configuration you use to configure things you know beforehand.

Releases also gives you the option to do runtime configuration with config/releases.exs.

This file is evaluated at each application boot. A few rules must be followed for this to work. From the docs:

  • It MUST import Config at the top instead of the deprecated use Mix.Config
  • It MUST NOT import any other configuration file via import_file
  • It MUST NOT access Mix in any way, as Mix is a build tool and it not available inside releases

This is a valid config/releases.exs file:

import Config
config :my_app, :secret_key, System.fetch_env!("MY_APP_SECRET_KEY")

See Application Configuration for details.


Releases can do a lot more than what I’ve shown, and has a bunch of options for customization, like bundling extra files into the release, adding custom start and stop scripts, configure the VM, cut a subset of your umbrella project as a release, hot code upgrade, and a bunch more.

It’s by far the best way to package your Elixir applications and you should use it.

Check out the release documentation for a more detailed walkthrough.