Releases
View SourceOne of the hurdles when dealing with Elixir releases is that only certain files are packaged into them. Any new ad-hoc files like our .env
files are not included by default. One way to ensure that our additional files get packaged into the release is to specify the :overlays
option in your mix.exs
. To do this we edit the mix.exs
file to specify the envs/
directory which contains your .env
files:
# mix.exs
def project do
[
app: :your_app,
# ...
releases: releases()
]
end
defp releases do
[
your_app: [
overlays: ["envs/"]
]
]
end
Core Concept: Overlays
When you specify a folder in the
overlays
option in yourmix.exs
, then the contents (and not the folder itself) will be copied to the root of the release.
During day-to-day development, your .env
files live inside the envs/
folder, but when a release is built, they get copied to the root of the release, so we cannot rely on relative paths in runtime.exs
! In our examples, we rely on Path.expand/2
, Path.absname/2
, and the presence of the RELEASE_ROOT
system environment variable to resolve our relative paths into absolute paths.
env_dir_prefix = System.get_env("RELEASE_ROOT") || Path.expand("./envs")
This is a simple trick to ensure that we always have a fully-qualified path to where our .env
files live. This pattern is repeated throughout the documentation because it is so important!
Putting your .env
files inside a folder named envs/
is merely a convention: you are free to store them where you wish, but keep in mind that it is easier to deal with folders than it is with individual files. See the documentation on Mix Release Overlays for more information.
Our config/runtime.exs
will look something like the following. Note that the folder referenced in the mix.exs
overlays section (envs/
) must correspond with the path referenced in config/runtime.exs
.
import Config
import Dotenvy
# For local development, read dotenv files inside the envs/ dir;
# for releases, read them at the RELEASE_ROOT
env_dir_prefix = System.get_env("RELEASE_ROOT") || Path.expand("./envs")
source!([
Path.absname(".env", env_dir_prefix),
Path.absname(".#{config_env()}.env", env_dir_prefix),
Path.absname(".#{config_env()}.overrides.env", env_dir_prefix),
System.get_env()
])
Remember that is always safer to use an absolute path. This is especially important when working with umbrella apps or Livebooks!
Umbrella Apps
Elixir Umbrella Projects consume configuration slightly differently due to how they are organized.
In particular, you have to be very careful about relative paths when working in an umbrella project. Depending on what you're doing, the path may be relative to a single application instead of relative to the root of the repository. As elsewhere, using Path.expand/1
and Path.absname/2
is a good way to anchor your config/runtime.exs
so it resolves to the same directory no matter if the app is running locally or as a release.
Once again, the winning pattern for your config/runtime.exs
will look something like this:
env_dir_prefix = System.get_env("RELEASE_ROOT") || Path.expand("./envs")
source!([
Path.absname(".env", env_dir_prefix),
Path.absname(".#{config_env()}.env", env_dir_prefix),
Path.absname(".#{config_env()}.overrides.env", env_dir_prefix),
System.get_env()
])
Changing the envs/ folder
What if you wish to keep your .env
files in some other folder? No problem. You just need to update your runtime.exs
and your mix.exs
so the :overlays
option corresponds to the folder name.
For example, here's what you would do if wanted to keep your .env
files inside a directory named xyz
:
# config/runtime.exs
env_dir_prefix = System.get_env("RELEASE_ROOT") || Path.expand("./xyz")
# ... etc...
# mix.exs
defp releases do
[
my_app: [
overlays: ["xyz/"]
]
]
end
Some languages/frameworks store .env
files at the root of the application, but this isn't easily compatible with Elixir releases. Rather than trying to push the river, we recommend choosing a sub-folder and leveraging the :overlays
option.