Deploying Elixir releases.

I have seen great posts about Elixir release deployments lately and I would like to share my experience deploying Elixir releases to production. After testing different approaches (from git cloning code in the target machine to building Docker images), I decided to go with, in my opinion, a simpler approach.

Deployment is critical

Deployment is one of the most important things in a project. It needs to be easy, fast and painless to rollback when things go wrong. Although it’s critical part of a project, it is sometimes overlooked. It’s not hard to find teams that deploy to a production-like environment only when they will release the project to the public, after months of development and thousands of commits.

Delaying a project deployment until you need to expose your project to the world, brings many unnecessary risks, like:

All those risks can be mitigated if the deployment starts early, is automated and it’s performed by everyone throughout the development phase.


The goals when defining the deployment strategy of this project, was to offer a really simple and fast way of getting a new release shipped. The TODO list while researching and implementing it was:



Before we get into the deployment, I think it’s important to give you some context about the project development cycle, since it has a direct impact on how the deploy is done. The numbers on the image means:

  1. The developer pushes her/his local changes to Github;
  2. CircleCI pulls the changes and run the automated tests. If all tests pass, then an Elixir release is created, using Exrm;
  3. The release is pushed to a AWS S3 bucket.

Some facts about this cycle:



The infrastructure that powers this project is quite standard, but let’s take a look on it into more details:

The infrastructure has its creation and setup automated by Ansible. All the information about the load balancers, web servers, databases, caches, etc are stored and managed by Ansible.

For that reason, using Ansible also for deployments seemed to be a really good fit for our case.


For a post about “deployment”, we have spent a considerable amount of time talking about different things, but not really getting into the main topic… deployment.


As mentioned earlier, we used Ansible for setting all the machines used by this project. Deploying a new version of the project, means running an Ansible Playbook, that contains all the tasks to be applied to the target machines.

That’s the command that someone (developer, web, Slack bot) runs in order to deploy a new version:

$ ansible-playbook --ask-vault-pass --extra-vars "version=[COMMIT]" -i [ENV] deploy.yml

Let’s break this command down into smaller parts:

When this command runs, several tasks are applied to the machines present in the environment inventory. Using the image above, let’s see what happens in each stage:

If you enjoyed this, you might also like

Elvio Vicosa

Hi, I'm Elvio. I’m an independent software developer consultant based in Berlin, Germany. I’ve spent the last 10+ years working in a wide range of software projects, from internal web dashboards to real-time applications used by millions of people.

More about me