Your dot-env file doesn’t do anything

As I’ve gotten more involved in various open source projects and helping out newbies, I’ve started to realize that many
frameworks rely on a .env file to hold configuration. However, as soon as a developer moves to a framework or language where this is not the case, they get very confused.

History

For many developers around today, .env files have been a standard configuration format for their entire career.
However, this has not always been the case. Before we had .env files, we had configuration files. When you started on a new job, you’d have to drop some configuration files at specific places on your disk. These files were often XML, JSON, or INI files.

.env files appear to be first introduced in December 2011, by Ruby/Heroku in PR #103 of Foreman. This was eventually implemented by bkeepers/dotenv as a standalone ruby gem, which became widely used across Ruby projects (eventually even replacing the implementation in Foreman).

Later that March 2012, a Python fork of Foreman implemented .env files, and then it was implemented in a JavaScript port later that October.

Finally, in January 2013, nearly one year later, we saw our first usage of .env files outside of Foreman, in vlucas/phpdotenv, which was quickly adopted by the Laravel community.

From there, it spread quickly to other languages and frameworks, becoming available as a package in most languages
by 2016.

Today, .env files are basically the de facto configuration format for applications.

What is an environment anyway?

Behind the scenes, a program inherits a set of environment variables from the operating system.
For example, what kind of terminal is running, where to find other programs (PATH), the hostname of the computer, the logged-in user, location of servers (such as on Linux, how to send sound to the sound card or display graphics), etc.

Environment variables are simple key-value pairs that your program can access at runtime. They’re not part of your code, and they don’t live in a file. If you spawn another program, it will inherit all the environment variables you’ve inherited plus any changes you’ve made.

You can try this out by skipping the .env file and manually setting the environment:

DB_PASSWORD=password123
DB_USER=app

and typing:

export DB_PASSWORD=password123 DB_USER=app

Then when you run your app; it will just work!

So, what about .env files?

If environment variables already exist in the operating system, why do we need .env files anyway?

Well, nobody wants to type export BLAH=BLAH FOO=BAR before starting the application. And with the advent of Docker, nobody wants to manually manage complex configuration files and risk baking them into the image.

If no special loader (like a dotenv library) is used, the .env file is ignored. It’s not magic. Frameworks execute this very early in the boot process so that it feels magical and invisible.

In the end, a .env file does nothing; it is just used by a loader to inject variables into your environment.

What to watch for

You need to be especially careful with .env files and/or storing secrets in your environment. These values are stored as plain text, so if your users can execute arbitrary code, they can extract API keys, database passwords, encryption keys, signing keys, etc.

It is usually better to use proper secrets management instead of environment variables. If you’re using something like docker compose, you can use secrets to share sensitive data with containers securely, without exposing them as plain-text environment variables.


Discover more from Somewhere Within Boredom

Subscribe to get the latest posts sent to your email.