Dotenv: Feature: Extending .env files

Created on 27 Aug 2020  ·  3Comments  ·  Source: motdotla/dotenv

Proposal

I'd like to propose a method by which .env files can "extend" or "inherit" from a base .env file located on the filesystem. This is a pattern found often in tooling such as TypeScript's tsconfig, ESLint, and even TSLint in this repo.

Semantics

# extends: .env.base

SOME_VALUE=batman

Use Case

Code-duplication is one of the battles that maintainers and contributors to large monorepos are constantly waging. In monorepos for microservices or other forms of apps, it's very common to see the following in a directory tree:

.env
.env.dev
.env.local
.env.stage

Where each file contains roughly the same information, somethings with minor modifications. This is especially prevalent with microservice monorepos leveraging serverless and serverless-offline. In most cases, the repeated set of data contains things like keys and tokens, and baseline or default data that'll be pulled from external sources like SSM, Redis, etc one deployed. It's common to see deploy-target-specific .env files as well.

This proposal is centered around allowing for a single source-of-truth at a root filesystem location (e.g. a monorepo root) containing _most_ default data needed.

Behavior

Consider this "base" file: _.env.base_

AUTH0_TOKEN=robin
OKTA_TOKEN=batman
SSM_PREFIX=joker

And this local _.env.local_ file, which extends .env.base

# extends: .env.base

DEPLOY_FRIDAY=true

At this point, process.env would contain; AUTH0_TOKEN, OKTA_TOKEN, SSM_PREFIX, and DEPLOY_FRIDAY. Say we needed a file for a staging environment that needed a slight modification to the default values, _env.stage_:

# extends: .env.base

SSM_PREFIX=stage

And process.env would contain all values from .env.base, but with SSM_PREFIX equal to stage, overriding the default value of joker.

Alternatives and Pitfalls

Calling Multiple Times

As @maxbeatty pointed out in https://github.com/motdotla/dotenv/issues/377#issuecomment-464411650, one could author a utility method to be shared in the environment that calls multiple times:

const dotenv = require(“dotenv”);

[“.env”, “.env.whatever”].forEach(path => dotenv.config({ path }));

This is certainly valid for small projects.

Pitfall

The pitfall with this approach are projects which leverage dotenv to automatically load and spin up a particular environment, such as serverless-plugin-dotenv (npm link). Any consumer of dotenv that is prepackaged would need to modify their behavior to take advantage of extending other .env files. That would create fragmentation in the expected use from one environment to another.

Argument For

I suggest that the value that this proposal would give to the community and userbase at large outweighs the code footprint and maintenance burden incurred by its addition. While small projects may not need this functionality, larger projects and specifically monorepos, are becoming more and more commonplace with companies such as Microsoft operating within monorepos almost exclusively. This would greatly reduce code duplication and be a large, further improvement to the developer experience.

Most helpful comment

I’d be on board. 👍

All 3 comments

I like this idea a lot at first glance. Need to dig in further but thumbs up!

I’d be on board. 👍

Coming from create-react-app, I'm surprised this is not implemented:
https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used

It looks like react-scripts extends dotenv functionality?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ycmjason picture ycmjason  ·  4Comments

AndersDJohnson picture AndersDJohnson  ·  4Comments

samayo picture samayo  ·  3Comments

AndersDJohnson picture AndersDJohnson  ·  5Comments

Vandivier picture Vandivier  ·  3Comments