.env file considerations

As Drumkit is a tool for scaffolding web projects and working with other tools, anyone who will be writing make targets for Drumkit will need to understand what kinds of things you can/cannot and should/should not do with the .env file.

The Rules

In summary, the golden rules for .env files are:

  1. A .env file must never be committed to a repo.
  2. A .env file should never contain more than one line with a particular variable name.
  3. Assume that the variables defined in the .env file are visible to all software and containers in that application.
  4. Assume the project using Drumkit will define their own .env make target.

… these will be discussed in more detail below.

Never commit a .env file

  1. The 12-factor app model, factor III, says to store configuration in environment variables (env vars)
    1. Examples of configuration given in that spec include DB connection information (host, port, username, password, schema), and API keys.
    2. You can think of the .env file like Drupal’s settings.php but for other apps.
  2. In general, passwords, secret keys, etc. shouldn’t be committed to a repo.
  3. Even if your app stores the secrets separately, remember that non-secret configuration often varies between environments.
  4. Even if the project you’re working on isn’t directly using .env to store config/secrets, other programs you or other developers use might automatically import variables from them and/or change their behaviour based on environment variables imported by other layers in the stack:
    1. Acquia Cloud
    2. Composer
    3. Ddev
    4. Docker
    5. Drush
    6. Lando
    7. platform.sh
    8. Pressflow and Pantheon-flavoured Drupal cores
    9. Symfony
    10. Terminus

Consequently, expect the .env file to not exist or be empty when your target is run.

No lines with duplicate variable names

The .env file format doesn’t have an official spec; the behaviour when two lines try to define the same variable differs based on the parser:

  • shell-based parsers treat the .env file like a .bashrc / .profile file, i.e.: where later assignments overwrite the value set by earlier assignments
  • similarly, the popular PHP parser, symfony/dotenv, and the popular Ruby parser, bkeepers/dotenv, also let the last definition take precedence because they store the collection of variables internally as a hash) (i.e. PHP array
  • contrarily, the popular JS parser, motdotla/dotenv (used in Lando, for example), uses the first definition only

Consequently, blindly appending lines to the .env file (e.g.: with a shell script’s >> pipe redirection operator) is very likely to lead to unexpected behaviour.

Note that the dotenv-linter/dotenv-linter project provides validation, fixing, and comparison tools for .env files.

Assume variables defined in .env are visibile to all apps

Simply put, many platforms deploy them to all parts of the app (usually, all containers), e.g.: Lando, Platform.sh, Acquia Cloud, etc.

Also note that some developers use direnv to automatically load variables into their current environment.

Assume the project will define its own .env make target

It’s reasonable to expect that a project will need its own way to compile its .env file to fit its particular stack of software, in the same way it’s reasonable to expect that a project will need to define its own build and install steps to fit its particular stack of software.

Put another way, let a project define it’s own .env: make target in drumkit/mk.d/; so in Drumkit itself, if you’re writing make targets to add/modify a .env file, prefix the make target names appropriately so they don’t collide.

More reading