This post describes Erlang’s sys.config and the equivalent config.exs in Elixir and how you can convert from config.exs to sys.config (the link is to a script that does this). I also talk a little about how you could use this to deploy Elixir projects using Chef.
Erlang releases use a file called
configuration values. This is the place to put your OTP applications’
configuration in addition to configuration for system applications
like the logger and
sasl. You can read
these values in your code using
A sys.config file is just an Erlang
application:get_env assumes that it is a
As an example, consider login credentials for an outside service. We
could store these in the sys.config file (
we’re building using rebar) as
something like the following.
1 2 3 4 5 6 7 8
We would then access this config in our application using the following.
1 2 3 4 5
Note that this approach only works for one environment. To use different credentials for testing, development, and production, we’d need to either come up with a config layout that allowed for multiple environments or swap out different files depending on the build environment. Either way is a bit cumbersome.
Elixir enriches our ability to configure OTP applications via the
DSL. This makes it very easy to have per-environment configurations
(e.g., testing, development, and production) and to compose config
Since we’re going to talk specifically about deployment to a
production environment, let’s make our
config/config.exs read from
different files depending on
Mix.env, which we can set with the
MIX_ENV environment variable.
1 2 3 4
That is, we just defer to the per-environment config file. Our development config might point to localhost.
1 2 3 4 5 6 7
Our testing config might use different credentials.
1 2 3 4 5 6 7
We have to at least have a
config/prod.exs file to be able to
compile the project, but we’ll end up using a different method below
to populate the production config at deployment time. So we can have
a dummy config file in source control.
1 2 3 4 5 6
Configuration values are accessed using
1 2 3 4 5 6
I highly recommend exrm to build releases for deploying Elixir projects. I highly recommend using a configuration management tool for deployment in general. I’m a fan of Chef, but most of this post isn’t specific to Chef.
exrm adds a Mix task called
mix release to your project. To build a
production release, you just run
MIX_ENV=prod mix release (after the
usual build cycle). This step creates an Erlang
which contains everything needed to run your app. Inside the release
is a sys.config file (
Application.get_env/3 will consult this file when your code is
mix release out-of-the-box will convert your
config/config.exs into a
sys.config file. This is fine if you
are not using configuration management, but you should really be using
configuration management ;). exrm handles this using a tool called
conform, which allows you to
.conf files inside your release. conform automatically builds
a new sys.config file each time you start your app (
conform is probably The Right Way To Do It. I’m going to present a simpler method here that also works. This might be helpful to you if you don’t have time to grok conform, or it might just be useful to you as a way of understanding part of what exrm and conform do under the hood.
If you look at the
exrm source code,
you’ll see that exrm uses
Mix.Config.read!/1 to read in the
appropriate config file and then simply
formats and writes the config term to a file.
The implementation of
is itself fairly straightforward and relies on
to turn the
.exs files into terms.
Converting a config.exs to a sys.config is essentially a matter of
to obtain a term and then writing it to disk. It could be implemented
simply using something like this.
1 2 3
I wrote a more fleshed-out Elixir script to generate a sys.config file from a config.exs file that includes some error handling and usage messages.
Deploying an Elixir project using Chef
This is how I use Chef to deploy Elixir applications. I won’t go go
into detail on how to install Erlang, Elixir, Mix, etc. I also won’t
cover how to build your code, which is fairly straightforward (the
mix compile, etc., but with
- Build your release using exrm’s
MIX_ENV=prod mix release. Use a build server if you have one, otherwise build in a temporary location. The output of the build process is a
.tar.gzfile of your release.
- Untar the release file into the deployment location and set appropriate ownership and permissions.
- Use a Chef template to generate a config.exs file for your
particular deployment environment. Have Chef install the
config.exs file alongside the release in
- Have Chef install the
in the deployment’s
PATHand make sure that it is executable.
- In the directory where the config.exs file lives (which is where
you want the sys.config file to end up), execute
MIX_ENV=prod elixir_to_sys_config config.exs > sys.config.
This way you can template your config.exs file in a way that is familiar to Elixir developers, and end up with a sys.config file that will work with your release app. If you structure your Chef cookbooks appropriately, you should be able to regenerate the config files without rebuilding the entire application.