Understanding Config in Elixir

Elixir uses a build tool called Mix, which allows you to define static global variables for your project inside a special file called config.exs.

A typical config.exs file looks something like this:

use Mix.Config

config MyApp,
  myVar: value,
  myVar2: value2

Inside your application, we then load the variables using a function called Application.get_env()/3. This allows us to access the static variables as we desire.

I recently started using Ecto, which uses such configuration to define connection parameters to the database. However, since I already had configuration for some variables inside my application, I was a bit confused about how to properly add the parameters for Ecto. Do I place it all inside the MyApp config? Do I place it inside a new config called EctoConfig? Tough to say.

Under the hood, config is actually just a key/value list. You may define multiple configs, but they are stored as a list of lists, one list for each key you define. For each key, you have another key/value list, which is the actual variables. An example will make this clear.

Let's assume I have an application called :status_app. I have a file called repo.ex which contains a module where I set up my Ecto repository:

defmodule StatusApp.Repo do
  use Ecto.Repo, otp_app: :status_app, adapter: Ecto.Adapters.Postgres

  def url do
    "ecto://postgres:postgres@localhost/sn"
  end

end

I also have a config.exs file:

config :status_app,
  sites: ["sheldonkreger.com", "prodrumblog.com"],
  interval: 2000

config :status_app, StatusApp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "sn",
  username: "postgres",
  password: "postgres",
  hostname: "localhost"

config :status_app, Foo,
  fooVar: "fooVal"

I like to think of :status_app as the top-level identifier for the config, and each additional config declaration as a separate namespace inside it. In this case, StatusApp.Repo is a module in my project.

The easiest way to see what this actually looks like is to use Application.get_all_env(:status_app):

IO.inspect(Application.get_all_env(:status_app)) returns:

[{StatusApp.Repo,
  [adapter: Ecto.Adapters.Postgres, database: "sn", username: "postgres",
   password: "postgres", hostname: "localhost"]}, {Foo, [foo: "fooVal"]},
 {:sites, ["sheldonkreger.com", "prodrumblog.com"]}, {:interval, 2000}]

I can access these variables using the key/value pair as an argument to Application.get_env()/3:

IO.inspect(Application.get_env(:status_app, :sites))

returns:

["sheldonkreger.com", "prodrumblog.com"]

We can give it just two arguments because it will default to the top-level list when we don't specify the key.

To drill down to Foo, we use Application.get_env()/3:

IO.inspect(Application.get_env(StatusApp, Foo, :fooVar)

Which returns:

[fooVar: "fooVal"]

By @Sheldon Kreger in
Tags : #Programming, #Elixir,