---
title: Configuring an Elm App with Environment Variables via webpack
teaser: 'Passing config from the environment to your Elm 0.18 app with webpack.

  '
tags: elm,web
author: Tom Wey
published_on: 2017-01-25
---

Often times applications require configuration values which don't belong in the
app or version control. [Keeping config separate from code] is one of the
principles of a 12-Factor app. When writing Ruby/Rails I tend to reach for the
[dotenv gem] and not give this much more thought.

An Elm app I've been working on makes HTTP requests to an external API. I
wanted to convert these from anonymous requests to sending an API key each
time. The API key was a clear case of configuration that I wanted to handle in
the environment, but I hadn't done this with Elm before.

[Keeping config separate from code]: https://12factor.net/config
[dotenv gem]: https://github.com/bkeepers/dotenv

## Configure webpack

The app is built and configured with [webpack]. There is no server-side
component. So the first step is to get webpack to pick up the config we need
from the environment.

We'll use the [dotenv npm package] to read from a local `.env` file
(remembering to add `.env` to our `.gitignore`):

<kbd>npm install dotenv --save</kbd>

Then require and configure dotenv in `webpack.config.js`:

```js
require('dotenv').config();
```

Now we need to use the [webpack EnvironmentPlugin] to make the environment
variables we need available. Add this to our list of plugins in
`webpack.config.js`:

```js
plugins: [
  ...,
  new webpack.EnvironmentPlugin(["ENV_VAR", "ANOTHER_ENV_VAR"])
]
```

We can now reference the environment variables we configured via `process.env`
in our JavaScript, for example `process.env.ENV_VAR`, and webpack will handle
these when compiling.

[webpack]: https://webpack.github.io/
[dotenv npm package]: https://www.npmjs.com/package/dotenv
[webpack EnvironmentPlugin]: https://github.com/webpack/docs/wiki/list-of-plugins#environmentplugin

## Passing Config to Elm as Flags

Elm has the concept of "flags" which the [JavaScript Interop] section of the
guide describes as: "static configuration for your Elm program". That sounds
like exactly what we need!

So when we're embedding our Elm app we can write the following to pass our
environment variables as flags:

```js
const elmApp = Elm.Main.embed(elmDiv, {
  config_value1: process.env.ENV_VAR,
  config_value2: process.env.ANOTHER_ENV_VAR
});
```

On the Elm side we'll use [Html.programWithFlags] to receive the flags. Our
main function will look something like this:

```elm
main : Program Flags Model Msg
main =
    Html.programWithFlags
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
```

Our `init` function will need to be modified to receive the flags. The argument
is of type `Flags` which we'll also need to define:

```elm
type alias Flags =
    { config_value1 : String
    , config_value2 : String
    }
```

Then, we update `init`'s type signature:

```elm
init : Flags -> ( Model, Cmd Msg )
```

In my app, handling the flags meant storing them in the app state to be used
later. Assuming your app state is of type `Model`, `init` will look something
like this, returning a `Model` and a `Cmd Msg`:

```elm
init : Flags -> ( Model, Cmd Msg )
init flags =
    ( Model flags.config_value1 flags.config_value2, Cmd.none )
```

That's it! When webpack compiles our app config will be read from the
environment, baked into the compiled JavaScript and available in our Elm app.
It's worth mentioning that these environment variables will be visible in the
source to users, so aren't suitable for anything sensitive.

[JavaScript Interop]: https://guide.elm-lang.org/interop/javascript.html
[Html.programWithFlags]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html#programWithFlags
