Any reason to use mix release/distillery with Docker, over mix phx.server?

As I understand it, mix release gives me:

  • a transportable release package (at least among the same OS).
  • the ability to hot-reload production releases.

Is there any advantage to using it compared to MIX_ENV=prod mix phx.server, if you’re deploying with Docker?

Why would I want to combine both?


  • already gives you a (even more?) transportable package, and you’re stuffing the release inside this anyway.
  • can’t really support hot-reloading in a container (at least, not in a way that doesn’t throw out why you’re using docker in the first place).

I guess it maybe protects you from having code changed in the image, recompiled and executed, either nefariously or by accident?

I assume there isn’t any real performance difference, outside of maybe a fractionally faster initial load (because it’s already compiled into beam code?)

I could understand “it gives me a nice clean directory structure and feels nice” as being reason enough, or maybe “it lets me be prepared for non-docker deploys if I ever want to”?

The doc covers it well: Why releases?

I really like being able to attach iex to the running app and use tools like recon or observer_cli, personally.

1 Like

Yeah I missed the mix docs :anguished: , actually this is probably the biggest thing:

Self-contained. A release does not require the source code to be included in your production artifacts. All of the code is precompiled and packaged. Releases do not even require Erlang or Elixir in your servers, as it includes the Erlang VM and its runtime by default. Furthermore, both Erlang and Elixir standard libraries are stripped to bring only the parts you are actually using.

Meaning your docker image can be even slimmer. Explains why some of the guides I was looking at use a “non-elixir” image after the build stage.

1 Like

Yeah, I like to use a multistage dockerfile, so I use the first to make the release (with all secrets, tokens, etc) then use an alpine with just the release. Or even build with musl and use a bare scratch image, so besides making it small, you narrow security risks found on libs

Is there a reason you prefer to build you secrets in over setting them via env vars? Less leaky into potential exploits or grand children?


If you run containerised systems, you do not hot load. Instead you spin up new containers and switch traffic over. Hot loading is for hosts that must stay up without moving traffic but nowadays that is usually the role of the load balancer.

Releases can still be hot loaded if built with Distillery AFAIK. But it is not easy.

One more benefit of releases is that you can have artefacts that are independent from the source. Maybe your source contains C code or some other external stuff that needs to be built. After the release is done you can copy it to another machine without bringing the C compiler and development headers with you. This minimises the exposed surface.

Lastly remember to run Docker containers, the images must be loaded to hosts and a smaller image will load faster. This means a rolling deployment that uses a smaller image completes quicker.

Currently I use a slim Debian image as the baseline, install Erlang from either ESL packages or GitHub, and Elixir from either source or precompiled archives from GitHub. Therefore the same Dockerfile can be configured to either build the system based on a stable set of runtimes or the latest versions of everything.

1 Like

Is this any different to copying docker images around, practically speaking? Though once you’re doing builds, you’re probably doing build stages at which point you might as well build an elixir release too.

I have mostly used the hexpm/* images. They have deb/ubuntu and alpine builds for just about any erlang-elixir combo you might want. No slimmed debian though, alpine being their “small base”.

I remember having issues with the official elixir images, though that was ages ago and I can’t remember what it was, which is what put me onto them. Maybe it was just they were a bit fat.

@soup you can try this tool and see for yourself. Every app is different. GitHub - wagoodman/dive: A tool for exploring each layer in a docker image

I avoid Alpine for now out of laziness. Slim Debian is adequate.

Very cool!

I wrote my experiences and finding if they help

The secrets used to build aren’t for the final image, just for building: private git repo access credentials, aws credentials for fetching configs and S3 content access, etc. All those things that aren’t needed for running.

1 Like