Elixir on green street signs at split in road. Purple mountains in background. Illustration.

Elixir Releases: Moving Quickly Past Elixir 1.8 and Distillery 2.0

Elixir 1.9 introduced built-in support for releases, a need that was previously served (and continues to be) by the Distillery package. An app being deployed with Distillery 2.0 on a pre-1.9 version of Elixir has two upgrade paths, so we’ll look at those options, discuss their pros and cons, and see what changes might be required to make the transition.

Can / Should We Still Use Distillery?

The first thing to understand is that Distillery is still an option. In fact, it supports some advanced configuration and tools that aren’t yet available with built-in releases. In particular, it offers some tools to help with hot upgrades and lets you add custom commands to your release executable.

If you rely on these features, or if you’re happy with Distillery and don’t want to switch, you can keep using it. See the instructions below for using Distillery with Elixir 1.9.

How Are Built-in Releases Different?

If you’re able to move to the built-in releases in Elixir 1.9, I think you’ll find that the new mechanism offers simpler solutions to two of the biggest sticking points with deploying releases, especially for Phoenix apps: configuration and database migrations.


Configuring releases themselves

Distillery uses a dedicated configuration file at rel/config.exs to configure releases, whereas Elixir releases are configured directly in mix.exs. If you’re happy with the default release settings, you don’t even have to add anything to mix.exs to build releases!

Runtime configuration for the app

Distillery allows you to overlay a runtime configuration file with some tweaks to your rel/config.exs. Because this method makes sense for so many apps, it’s supported natively in the new built-in releases: Just put your runtime configuration (with System.get_env() calls to pull in environment variables) in config/releases.exs and it’s automatically loaded and merged in when the release is started.

Database migrations (and other one-off jobs)

Distillery provides a mechanism for adding custom commands to your release executable, which is useful for things like migrations and administrative tasks. It works great, but it can feel like a lot of configuration and boilerplate. Again simplifying things, Elixir releases include an eval command that lets you run any app code with a simple invocation. In addition to simpler configuration, this method doesn’t even necessarily require you to know which code you might want to run before you build your release.

Instructions: Using Distillery with Elixir 1.9

If you want to stick with Distillery but upgrade Elixir, you’ll need to upgrade Distillery to version 2.1, which makes some adjustments to avoid collisions between the two release systems. The changes also require some adjustments in the app:

  • When building releases, you’ll need to use mix distillery.release because mix.release invokes the built-in release mechanism.
  • Instances of Mix.Releases.... will need to be replaced with Distillery.Releases... in rel/config.exs and elsewhere.

That should be all you need to keep using your existing Distillery release configuration in Elixir 1.9 and beyond.

Instructions: Moving from Distillery to Elixir 1.9 Releases

If you’re not using any advanced configuration with Distillery and want to switch, there are several changes required to move to the new system. I think you’ll find that most of them are painless and lead you to a simpler setup, but YMMV, especially if you’re doing fancy or nonstandard stuff in your elixir releases (see above).

Startup Command

In Distillery, you’d use the start command to run the app in the background and foreground to run it in the foreground. In 1.9 releases, start runs the app in the foreground while daemon runs it in the background.

So start is available in both systems but means something very different! You can find the full list of commands here.

Migration Scripts & Tools

To run this kind of job, you can invoke code directly via ...bin/app_name eval "MyApp.MyModule.func()" instead of custom commands. Any files related to those custom commands can be removed.

Release Config

If you have multiple releases defined in rel/config.exs or use other custom configuration options, you’ll need to transfer those to mix.exs. The full set of options is documented here.

Runtime Config

If you’re using a file like rel/config/runtime_config.exs, move it to config/releases.exs and make sure it follows these rules.

VM Config

Running mix release.init in Elixir 1.9 generates rel/vm.args.eex, rel/env.sh.ex, and env.bat.eex. vm.args.eex contains the following comment:

-mode/-name/-sname/-setcookie are configured via env vars,

do not set them here

If you want to adjust other vm settings, you can do that in vm.args.eex, but the ones listed above, being often environment and host-specific, can be managed by simply setting the right environment variables. See the full list of release-specific environment variables for more info.

Remove extra files

Because Distillery’s configuration is slightly more powerful and verbose, there are some extra files that can be removed when moving to 1.9 releases. They include:

  • rel/config.exs
  • Anything in rel/commands (and the folders itself)
  • rel/plugins (assuming it’s empty)
  • Your old custom vm.args file, if you set one up

Bottom Line: 1.9 is a Big Step Forward for Elixir

Making the transition to Elixir 1.9 releases has been pretty painless for our apps so far. We’ve found the new system meets our needs and streamlines our configuration and deployment story. Congrats to everybody who made it happen!

If you enjoyed this article post on elixir releases, you can check out more of my writing here!

We're building an AI-powered Product Operations Cloud, leveraging AI in almost every aspect of the software delivery lifecycle. Want to test drive it with us? Join the ProdOps party at ProdOps.ai.