Skip to content

class Athena::Dotenv
inherits Reference #

Using Environment variables (ENV vars) is a common practice to configure options that depend on where the application is run; allowing the application's configuration to be de-coupled from its code. E.g. anything that changes from one machine to another, such as database credentials.

.env files are a convenient way to get the benefits of ENV vars, without taking on the extra complexity of other tools/abstractions until if/when they are needed. The file(s) can be defined at the root of your project for development, or placed next to the binary if running outside of a dev environment. The Athena::Dotenv component parses the .env files to make ENV vars stored within them accessible.

Getting Started#

If using this component within the Athena Framework, it is already installed and required for you. Checkout the manual for some additional information on how to use it within the framework.

If using it outside of the framework, you will first need to add it as a dependency:

    github: athena-framework/dotenv
    version: ~> 0.1.0

Then run shards install, being sure to require it via require "athena-dotenv".


All usage involves using an Athena::Dotenv instance. For example:

require "athena-dotenv"

# Create a new instance
dotenv =

# Load a file
dotenv.load "./.env"

# Load multiple files
dotenv.load "./.env", "./"

# Overrides existing variables
dotenv.overload "./.env"

# Load all files for the current $APP_ENV
# .env, .env.local, and .env.$APP_ENV.local or .env.$APP_ENV
dotenv.load_environment "./.env"
A Athena::Dotenv::Exceptions::Path error will be raised if the provided file was not found, or is not readable.


ENV vars should be defined one per line. There should be no space between the = between the var name and its value.

DATABASE_URL=mysql://db_user:[email protected]:3306/db_name

AAthena::Dotenv::Exceptions::Format error will be raised if a formatting/parsing error is encountered.


Comments can be defined by prefixing them with a # character. Comments can defined on its own line, or inlined after an ENV var definition.

# Single line comment

BAR=BAZ # Inline comment

Unquoted values, or those quoted with single (') quotes behave as literals while double (") quotes will have special chars expanded. For example, given the following .env file:

require "athena-dotenv" "./.env"

ENV["UNQUOTED"]      # => "FOO\\nBAR"

Notice how only the double quotes version actually expands \n into a newline, whereas the others treat it as a literal \n.

Quoted values may also extend over multiple lines:


Both single and double quotes will include the actual newline characters, however only double quotes would expand the extra newline in BAR\n.


ENV vars can be used in values by prefixing the variable name with a $ with optional opening and closing {}.



The order is important when using variables. In the previous example FOO must be defined BAZ which must be defined before BIZ. This also extends to when loading multiple files, where a variable may use the value in another file.

Default values may also be defined in case the related ENV var is not set:


This would set the value of DB_USER to be root, unless DB_USER is defined elsewhere in which case it would use the value of that variable.


Shell commands can be evaluated via $().


Commands are currently not supported on Windows.


File Precedence#

The default .env file defines ALL ENV vars used within an application, with sane defaults. This file should be committed and should not contain any sensitive values.

However in some cases you may need to define values to override those in .env, whether that be only for a single machine, or all machines in a specific environment.

For these purposes there are other .env files that are loaded in a specific order to allow for just this use case:

  • .env - Defines all ENV vars, and their default values, used by the application.
  • .env.local - Overrides ENV vars for all environments, but only for the machine that contains the file. This file should NOT be committed, and is ignored in the test environment to ensure reproducibility.
  • .env.<environment> (e.g. .env.test) - Overrides ENV vars for only this one environment. These files SHOULD be committed.
  • .env.<environment>.local (e.g. .env.test.local) - Machine-specific overrides, but only for a single environment. This file should NOT be committed.

See #load_environment for more information.


Real ENV vars always win against those created in any .env file.


Environment specific .env files should ONLY to override values defined within the default .env file and NOT as a replacement to it. This ensures there is still a single source of truth and removes the need to duplicate everything for each environment.


.env files are mainly intended for non-production environments in order to give the benefits of using ENV vars, but be more convenient/easier to use. They can of course continue to be used in production by distributing the base .env file along with the binary, then creating a .env.local on the production server and including production values within it. This can work quite well for simple applications, but ultimately a more robust solution that best leverages the features of the server the application is running on is best.


VERSION = "0.1.0"#


.new(env_key : String = "APP_ENV")#

View source


#load(*paths : String | Path) : Nil#

Loads each .env file within the provided paths.

require "athena-dotenv"

dotenv =

dotenv.load "./.env"
dotenv.load "./.env", "./"
View source

#load_environment(path : String | Path, env_key : String | Nil = nil, default_environment : String = "dev", test_environments : Enumerable(String) = {"test"}, override_existing_vars : Bool = false) : Nil#

Loads a .env file and its related additional files based on their precedence if they exist.

The current ENV is determined by the value of APP_ENV, which is configurable globally via .new, or for a single load via the env_key parameter. If no environment ENV var is defined, default_environment will be used. The .env.local file will NOT be loaded if the current environment is included within test_environments.

Existing ENV vars may optionally be overridden by passing true to override_existing_vars.

require "athena-dotenv"

dotenv =

# Use `APP_ENV`, or `dev`
dotenv.load_environment "./.env"

# Custom *env_key* and *default_environment*
dotenv.load_environment "./.env", "ATHENA_ENV", "qa"
View source

#overload(*paths : String | Path) : Nil#

Same as #load, but will override existing ENV vars.

View source

#parse(data : String, path : String | Path = ".env") : Hash(String, String)#

Parses and returns a Hash based on the string contents of the provided data string. The original .env file path may also be provided to path for more meaningful error messages.

require "athena-dotenv"

path = "/path/to/.env"
dotenv =

File.write path, "FOO=BAR"

dotenv.parse, path # => {"FOO" => "BAR"}
View source

#populate(values : Hash(String, String), override_existing_vars : Bool = false) : Nil#

Populates the provides values into the environment.

Existing ENV vars may optionally be overridden by passing true to override_existing_vars.

require "athena-dotenv"

ENV["FOO"]? # => nil{"FOO" => "BAR"})

ENV["FOO"]? # => "BAR"
View source