Loads environment variables from dotenv files

Version on this page:
LTS Haskell 9.17:
Stackage Nightly 2017-12-10:
Latest on Hackage:
MIT licensed by Justin Leitgeb
Maintained by

Module documentation for

Build Status Hackage

Dotenv files for Haskell

In most applications, configuration should be separated from code. While it usually works well to keep configuration in the environment, there are cases where you may want to store configuration in a file outside of version control.

"Dotenv" files have become popular for storing configuration, especially in development and test environments. In Ruby, Python and Javascript there are libraries to facilitate loading of configuration options from configuration files. This library loads configuration to environment variables for programs written in Haskell.


In most cases you will just add dotenv to your cabal file. You can also install the library and executable by invoking stack install dotenv.


Set configuration variables in a file following the format below:


Then, calling Dotenv.load from your Haskell program reads the above settings into the environment:

import qualified Configuration.Dotenv as Dotenv
Dotenv.loadFile False "/path/to/your/file"

After calling Dotenv.load, you are able to read the values set in your environment using standard functions from System.Environment such as lookupEnv and getEnv.

NOTE: Empty environment variables

If you need to have empty environment variables in your configuration, you can use something like the code below:

fromMaybe "" <$> lookupEnv "ENV_VAR"

Currently, dotenv-hs doesn't allow you to set empty environment variables, because of setEnv from our System.Environment. This is bug reported in GHC ticket. We have had many dicussions about this. Fortunately, there is already some work for this issue in GHC Phabricator.

Variable substitution

In order to use compound env vars use the following sintax within your env vars ${yourenvvar}. For instance:


Running it on the CLI:

$ dotenv "echo $DATABASE"

Command substitution

In order to use the standard output of a command in your env vars use the following sintax $(your_command). For instance:


Running it on the CLI:

$ dotenv "echo $DATABASE"


The first argument to loadFile specifies whether you want to override system settings. False means Dotenv will respect already-defined variables, and True means Dotenv will overwrite already-defined variables.

Advanced Dotenv File Syntax

You can add comments to your Dotenv file, on separate lines or after values. Values can be wrapped in single or double quotes. Multi-line values can be specified by wrapping the value in double-quotes, and using the "\n" character to represent newlines.

The spec file is the best place to understand the nuances of Dotenv file parsing.

Command-Line Usage

You can call dotenv from the command line in order to load settings from one or more dotenv file before invoking an executable:

$ dotenv -f mydotenvfile myprogram

The -f flag is optional, by default it looks for the .env file in the current working directory.

$ dotenv myprogram

Aditionally you can pass arguments and flags to the program passed to Dotenv:

$ dotenv -f mydotenvfile myprogram -- --myflag myargument


$ dotenv -f mydotenvfile "myprogram --myflag myargument"

Also, you can use a --example flag to use dotenv-safe functionality so that you can have a list of strict envs that should be defined in the environment or in your dotenv files before the execution of your program. For instance:

$ cat .env.example

$ cat .env

$ echo $FOO

This will fail:

$ dotenv -f .env --example .env.example "myprogram --myflag myargument"
> dotenv: Missing env vars! Please, check (this/these) var(s) (is/are) set: BAR

This will succeed:

$ export BAR=123 # Or you can do something like: "echo 'BAR=123' >> .env"
$ dotenv -f .env --example .env.example "myprogram --myflag myargument"

Hint: The env program in most Unix-like environments prints out the current environment settings. By invoking the program env in place of myprogram above you can see what the environment will look like after evaluating multiple Dotenv files.


Justin Leitgeb



(C) 2015-2017 Stack Builders Inc.




  • Allow .env empty files


  • Add support for command substitution on env vars.


  • Set .env file as default file for environment variables.
  • Add --version flag to check the version of dotenv that is in use.


  • Add dotenv-safe functionality
  • Add the Config type with options to override env variables, and setting the path for .env and .env.example files.
  • Changed loadFile function to get Config with the paths for the .env file and the .env.example file.


  • Use Megaparsec 6.0
  • Dropped support for GHC 7.6


  • Allow optparse-applicative 0.14


  • Add support for variable expansion. Thanks to حبيب الامين (GitHub: habibalamin) for making this contribution.


  • Add the option to pass arguments to the program passed to Dotenv. Thanks to Oleg Grenrus (GitHub: phadej) for making this contribution.


  • Made interface more polymorphic so the functions works in any instance of MonadIO, not only IO. This should reduce amount of lifting in some cases.

  • Added onMissingFile helper to deal with possibly missing files.

  • Parser was rewritten to take full advantage of Megaparsec. hspec-megaparsec is now used for testing of the parser.

  • Dropped support for GHC 7.4.


  • Allow optparse-applicative 0.13


  • Remove unnecessary package dependencies.


  • Reverted change to Data.Text in favor of String, for maintaining compatibility with common Haskell system libraries. Added separate interface for parsing a file into tuples containing Data.Text values. Thanks to Daisuke Fujimura (GitHub: fujimura).
  • Fixed parsing of CRLF characters for Windows users.

Dotenv (deprecated)

  • Changed public interfaces to use Data.Text.
  • Added function parseFile to read dotenv file without modifying the environment. Thanks to Daisuke Fujimura (GitHub: fujimura) for making this contribution.


  • First public release.
comments powered byDisqus