class Athena::Dotenv
inherits Reference
#
All usage involves using an Athena::Dotenv
instance.
For example:
require "athena-dotenv"
# Create a new instance
dotenv = Athena::Dotenv.new
# Load a file
dotenv.load "./.env"
# Load multiple files
dotenv.load "./.env", "./.env.dev"
# 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"
Athena::Dotenv::Exception::Path
error will be raised if the provided file was not found, or is not readable.
Syntax#
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::Exception::Format
error will be raised if a formatting/parsing error is encountered.
Comments#
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
FOO=BAR
BAR=BAZ # Inline comment
Quotes#
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:
UNQUOTED=FOO\nBAR
SINGLE_QUOTES='FOO\nBAR'
DOUBLE_QUOTES="FOO\nBAR"
require "athena-dotenv"
Athena::Dotenv.new.load "./.env"
ENV["UNQUOTED"] # => "FOO\\nBAR"
ENV["SINGLE_QUOTES"] # => "FOO\\nBAR"
ENV["DOUBLE_QUOTES"] # => "FOO\n" + "BAR"
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:
FOO="FOO
BAR\n
BAZ"
Both single and double quotes will include the actual newline characters, however only double quotes would expand the extra newline in BAR\n
.
Variables#
ENV vars can be used in values by prefixing the variable name with a $
with optional opening and closing {}
.
FOO=BAR
BAZ=$FOO
BIZ=${BAZ}
Warning
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:
DB_USER=${DB_USER:-root}
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.
Commands#
Shell commands can be evaluated via $()
.
Note
Commands are currently not supported on Windows.
DATE=$(date)
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 thetest
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.
Note
Real ENV vars always win against those created in any .env
file.
Tip
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.
Production#
.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.
Constants#
VERSION = "0.1.3"
#
Constructors#
.load(path : String | Path = ".env", *paths : String | Path) : self
#
Convenience method that loads one or more .env
files, defaulting to .env
.
Methods#
#load(*paths : String | Path) : Nil
#
Loads each .env
file within the provided paths.
require "athena-dotenv"
dotenv = Athena::Dotenv.new
dotenv.load "./.env"
dotenv.load "./.env", "./.env.dev"
#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 = Athena::Dotenv.new
# Use `APP_ENV`, or `dev`
dotenv.load_environment "./.env"
# Custom *env_key* and *default_environment*
dotenv.load_environment "./.env", "ATHENA_ENV", "qa"
#overload(*paths : String | Path) : Nil
#
Same as #load
, but will override existing ENV vars.
#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 = Athena::Dotenv.new
File.write path, "FOO=BAR"
dotenv.parse File.read(path), path # => {"FOO" => "BAR"}
#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
Athena::Dotenv.new.populate({"FOO" => "BAR"})
ENV["FOO"]? # => "BAR"