TL;DR; Elixir is a compiled language and as such, every information needed for the code to compile needs to be available at, well…, compilation time. If your application depends on the configuration to run, you’ll need to make it available before releasing it.
The way to env vars
I’m writing a small, barebones, web services using elixir-plug and here are the main mistakes I made trying to specify the Router’s HTTP port using environment variables
Mistake #1: Using the wrong key in the configuration file
My application is called
Closeconnection and that was my configuration file.
1 2 3 use Mix.Config config Closeconnection, port: 3000
Whenever I tried to access the value of port using,
Application.get_env(:closeconnection, :port) I’d get back
nil as return. Once I changed to
config :closeconnection, port: 3000 it worked 🎉!
Mistake #2: Env vars are always String
That’s the code to start the server:
1 2 3 4 5 6 Plug.Adapters.Cowboy.child_spec( :http, Router, , port: Application.get_env(:closeconnection, :port) )
Application.get_env would get the information from the config and the config would get the information from the system with
System.get_env, so far so good.
$ PORT=4444 mix run 💥
The problem here is that the function
Plug.Adapters.Cowboy.child_spec/4 expects port to be an integer but
System.get_env (and in turn
String. After casting it to integer with
String.to_integer(Application.get_env(:closeconnection, :port)) it worked 🎉!
Mistake #3: Declaring the Env variable only at Run time
I wanted to get the value of port from the command line and not “hard coded” in a configuration file. Luckily, that’s not so hard to do, I just changed my configuration file to the following:
1 2 3 use Mix.Config config :closeconnection, port: System.get_env("PORT")
I tested the app, ran it locally with
PORT=4444 mix run and all seemed to work. Life was good again. I, then, went ahead and bundled the app in a binary using distillery which allows the app to run in any machine with erlang installed. Cool!
$ mix release ... $ ./build/dev/rel/closeconnection start 💥
The app wouldn’t start. After some debugging I found the
PORT was nil. But why!? That’s when remembering that Elixir is a compiled language comes in handy. My app relied in that piece of information (the port) to run, but not to compile, so I needed to pass it during compilation time.
$ PORT=4444 mix release ... $ ./build/dev/rel/closeconnection start 🎉
- Check if config you specified has the same key in the configuration file and in the
- Values coming from
System.get_envare always String (or
nilif not found)
- Env variables must be available at compilation time
Did you have a similar experience with Elixir? How do you manage your env variables? Let me know in the comments below!