Continue Using .env Files As Usual.
Tags: javascript, webdev, node
Published: 2022-09-24 13:46:35

---
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ivon50sdm1h96tluxpr.jpg
---

## Table Of Content (TOC). <a name="toc"></a>

* [Introduction.](#introduction)
* [1. Storing The .env File.](#storing-the-dotenv-file)
* [2. Updating a secret config.](#updating-a-secret-config)
* [3. Versioning.](#versioning)
* [Why `.env` file?](#why-dotenv-file)
* [Securing an .env file?](#securing-a-dotenv-file)
* [Advantages of using an `.env` file.](#advantages-of-using-a-dotenv-file)
* [Problems With Centralized Config Servers.](#problems-with-centralized-config-servers)
* [Conclusion.](#conclusion)
* [Bonus For Linux Enjoyers.](#bonus)

## 👉 Inroduction. <a name="introduction"></a>

We all know that first impressions are essential. The same goes for the first sentence of an article. In fact, it might be even more critical for an article because the first sentence is what will determine whether or not someone keeps reading.

But, in the case of [this article](https://dev.to/gregorygaines/stop-using-env-files-now-kp0), stating that working with large-scale systems would make you eligible enough to write about the topic is quite funny. This sentence has a psychological effect that makes readers feel like they are stupid and doomed, assuming they are all working on "Hello World" kind of projects.

Needless to say, as a reader, you may start to wonder: "What in the world does he mean when he said he has worked on large-scale systems?" I mean, literally, everyone is doing that nowadays. I don't think it can be used as a unique selling point or anything; nearly everyone has experience working with large-scale enterprise systems.

Even the most junior engineer has likely worked on a system that processes millions of requests/records daily. So what makes working on large-scale systems so unique? What makes you think your experience is worth anything special? You need to show that you have something unique to offer; otherwise, it's just another redundant sentence in your article. But anyway, let's move on.

Let's start by criticizing each point that looks like a problem with `.env` files when in reality, they are not problems at all but rather misconceptions.

## 👉 1. Storing the .env file. <a name="storing-the-dotenv-file"></a>

##### 🔝 [Go To TOC](#toc)

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xsokmzz915gls2yr4v1.png">
  <figcaption>Everything in linux is a file.</figcaption>
</figure>

This section started by:

> The problem is well... It's a file.

Well, I don't know about you and which OS you are currently using, but [everything in Linux is literally a file](https://www.linux.org/threads/in-linux-everything-is-a-file.4251/). This includes devices, processes, sockets, files, pipes, etc. However, the critical question is: what's wrong with it?

If you think it is not a good idea to make everything in Linux a file, including env vars, then you have to invite Linus for a debate and discuss the drawbacks of this approach. Provide your solution instead. 

Additionally, containers are based on Linux cgroups, namespaces, and other components, which means that they are also built around the concept of everything being a file. This makes Linux a very powerful os for running containers, as everything can be easily managed and controlled via files.

Moreover, everything in k8s is also a file, a YAML file. This concept makes k8s extraordinarily flexible and customizable. You can literally configure anything you want, and there are very few restrictions.

As the author is now working at Google, he has the chance to discuss with the brains behind k8s, argue with them about the drawbacks of files, and share his insights with us. We would love to hear his thoughts on this matter!

Besides, the question is: Who is committing an `.env` file to public repos? Literally, no one with at least two brain cells is willing to commit an env file, as far as I know. [Some developers on github](https://github.com/juregrandovec/express-mvc/commit/3ba9965739d760ec424b043116bd8765a870914a), [me included](https://github.com/wiseaidev/chat/blob/main/backend/.env.example), commits only templates of this file to help other understand the env vars used in a particular project. There is a `.gitignore` file in case you want to ignore that file from being committed; that's the basics, and everyone should be aware of that.

Even if you don't like to include a `.gitignore` file for each new repo, you can add a new entry in a [global `~/.gitignore` file](https://stackoverflow.com/questions/7335420/global-git-ignore), so you don't have to worry about including that file each time when creating a new repo.

Now, you may wonder: well, how to share the `.env` file with other developers? And the answer goes like this: If you're collaborating with other people on a project, it's essential to keep your `.env` file private so that only invited collaborators can see it(e.g., create a private repo for the `.env` file).

## 👉 2. Updating a secret config <a name="updating-a-secret-config"></a>

##### 🔝 [Go To TOC](#toc)

I have never had access to updating a database password throughout my years working at companies. This is because there is always someone responsible for managing databases. Having access to update passwords would be a huge responsibility and could potentially lead to security breaches.

So, having someone responsible ensures that passwords are kept up to date and secure. It also means that if there is ever a problem with a password, there is only one person who needs to be contacted to fix it. This system may not be perfect, but it is the best way to protect company data.

All I can get are env names and use them within the app. That's it; Nothing else. This is why having a designated person is so important. Not only does it make life easier for employees, but it also helps keep everyone on the same page, safe, and secure.

## 👉 3. Versioning. <a name="versioning"></a>

##### 🔝 [Go To TOC](#toc)

Environment variables are not parts of the app code, so there is no need to version them. I have never used an app that keeps track of password history changes, and I see no reason why this would be necessary. They are just static values and don't change often.

But in any case, if you want to apply versioning to an `.env` file stored in a private repo, you can release a new version for each value change.

Then the author proceeds to provide a solution to a problem that doesn't exist. What's even funnier is that the solution leads to potential security risks. So basically, let someone else do it for you if you don't want to manage your secrets, not to mention that the party you share with is a centralized place. If it gets compromised, everyone's secrets in the whole damn world will get exposed.

So, everyone would instead have control over their secrets and not depend on third parties, especially in case of sensitive information.

## 👉 Why `.env` file? <a name="why-dotenv-file"></a>

##### 🔝 [Go To TOC](#toc)

We, as developers, use `.env` files to store environment variables. These files are not meant for use in production and should be removed/ignored from the codebase before deploying it to production. If you have ever worked with containerized apps, you would know that.

The idea of having an `.env` file in a repo is to have an example or template of the required env vars as a form of documentation that tells which variables are needed for this project. They could have default values, but as we all know, they should never contain plain text credentials. It is like telling other developers that X, Y, and Z are used in this app as env vars. Having an `.env` template file in a repo sets expectations for other developers and maintains best practices. This would help new developers clone the repo and work with it without any hassle.

The application should then load this template `.env` and look for other places to override these default values depending on the current environment. This could be a `.env.local` file on the system, already set system environment variables, or variables from config storage. If you ever used Jenkins or built a DevOps pipeline, you probably encountered that.

We get it; it is not a good idea to use `.env` files in production because they can contain sensitive information like database passwords, API keys, and other credentials that should not be accessible to others.

However, one thing you can do though is to take additional precautions to keep your `.env` file or env vars secure and safe.

## 👉 Securing an .env file? <a name="securing-a-dotenv-file"></a>

##### 🔝 [Go To TOC](#toc)

An `.env` file is not secure if it's being used for production purposes. Anyone with access to the machine can view and modify it without permission.

However, you can set permissions for this file. I don't know about you, but you can use the following command to secure your env file:

```sh
chmod 0400 .env
```

Doing so, the `.env` file can only be read by the owner and no one else. You can use this command in a docker file if you need to copy it into the docker image. But, usually, it is not encouraged to do so. In the case of docker, secrets can be used, which are discussed later in the following sections.

If you have ever worked with [laravel](https://laravel.com/docs/9.x/configuration), the chances of using the `.env` file in production are high. And that is ok as long as you keep it secure. The following is a typical security practice used by Laravel developers:

```sh
#Disable index view
options -Indexes

#hide a Specific File

<Files .env>
order allow, deny
Deny from all
</Files>
```

In docker, you can import [env variables](https://docs.docker.com/compose/environment-variables/#using-the---env-file--option) with docker-compose using the following command:

```sh
docker-compose --env-file .env
```

Or you can specify the env file within the YAML file:

```yaml
version: "3.8"

services:
  frontend:
    image: awesome/webapp
    env_file:
      - .env     # path to your .env file
```

If you want to pass [secrets](https://docs.docker.com/compose/compose-file/#secrets), then you can define a secrets section within the `docker-compose.yaml` file:

```yaml
version: "3.8"

services:
  frontend:
    image: awesome/webapp
    secrets:
      - server-certificate

secrets:
  server-certificate:
    file: ./server.cert
```

If you are building a docker image, you can create an env file to store secrets and mount the file to the container.

```sh
PYPI_USER=dev_bro
PYPI_PASS=my_super_duper_secret_token
```

Now you can load the `.env` file and give it an id called `my_secret`. We can use this key in the next step to access the `.env` file. Then modify your Dockerfile so that it mounts the secrets.

```sh
FROM python:3.9-slim-buster
COPY build-script.sh .
RUN --mount=type=secret,id=my_secret . ./build-script.sh
```

```sh
# build-script.sh:
cat /run/secrets/my_secret
```

Now, you can build and inject the `.env` file into the container:

```sh
export DOCKER_BUILDKIT=1
docker build --progress=plain -t "my_app" --secret id=my_secret,src=.env . --no-cache
```

Note that these env vars are not logged into the history, so running the following command won't reveal the secrets:

```sh
docker history my_app --no-trunc | grep PYPI_PASS
```

For more info about secrets in docker, you can refer to [this piece of docs](https://docs.docker.com/develop/develop-images/build_enhancements/#new-docker-build-secret-information).


Additionally, if you are using k8s, there are API objects like [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-a-configmap) to store config data and [Secrets](https://kubernetes.io/docs/tasks/configmap-secret/managing-secret-using-config-file/) to store confidential data. Or, [you can set env vars within a pod](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/). 

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod

spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "env" ]
      env:
        # Define the environment variable
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              # The ConfigMap containing the value you want to assign to SPECIAL_LEVEL_KEY
              name: special-config
              # Specify the key associated with the value
              key: special.how
  restartPolicy: Never
```

I have worked on many projects, some of which are open source. In some projects like [this one](https://github.com/wiseaidev/frozndict), I used [env vars](https://github.com/wiseaidev/frozndict/blob/016dcaa5adafa4223101538684335085dd1da798/.circleci/config.yml#L34) to store my secrets within circleci to publish a new version to PyPi automatically.

Moreover, for security reasons, I have noticed that PyPi has implemented a feature to allow authentication with their servers through using [api tokens](https://pypi.org/help/#apitoken) without the need for passwords anymore. So, now you can store encrypted PyPi credentials within env vars.

If you ever built a pipeline with Azure DevOps, you probably wanted to copy the `.env` file into the docker image using [Copy files task](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/copy-files?view=azure-devops&tabs=yaml): 

```yaml
steps:
- task: DownloadSecureFile@1
  displayName: 'Download secure file'
  inputs:
    secureFile: .env

- task: CopyFiles@2
  displayName: 'Copy Files to: $(System.DefaultWorkingDirectory)'
  inputs:
    SourceFolder: '$(Agent.TempDirectory)'
    Contents: .env
    TargetFolder: '$(System.DefaultWorkingDirectory)'
```

If you are using Jenkins, you can inject env variables using plugins like [envinject](https://plugins.jenkins.io/envinject/)

So, as you can see, it depends on the type of applications you are dealing with to follow the best practices to securely use an `.env` file.

## 👉 Advantages of using an `.env` file. <a name="advantages-of-using-a-dotenv-file"></a>

##### 🔝 [Go To TOC](#toc)

There are so many advantages to using `.env` files or environment variables, such as:

- **Ease of management**: Having worked on so many backend projects, I find `.env` files easy to manage because they are self-explanatory and don't require additional documentation.

- **Simplicity**: `.env` files simplify the task of managing different backends because it allows you to configure all the necessary settings for each backend in one place.

- **Debugging and testing**: It becomes easier because developers can modify a specific environment for each application.

- **Sharing**: `.env` files templates like `.env.example` can be added to git repositories, so other developers on the team know what environment variables were used for that project.

## 👉 Problems With Centralized Config Servers. <a name="problems-with-centralized-config-servers"></a>

##### 🔝 [Go To TOC](#toc)

Several potential problems can occur when using a centralized config server for an application. If the server goes offline, the app will not be able to start. If the server updates and renames an environment variable that the app is not expecting, the app may crash on the next restart. Finally, if the app is hosted offline, it will not be able to start without an internet connection to load the env vars from outside.

## 👉 Conclusion. <a name="conclusion"></a>

##### 🔝 [Go To TOC](#toc)

At the end of the day, `.env` files and environment variables work fine and are simple enough for development purposes, as long as you know how to use these files. However, it is totally up to you to choose the best approach that aligns with your personal preferences, what works best for your particular application or system.

## 👉 Bonus For Linux Enjoyers. <a name="bonus"></a>

##### 🔝 [Go To TOC](#toc)

On Linux, if you want to print out a specific environment variable, like `LOGNAME`, of the current process, then run the following command:

```sh
strings /proc/$$/environ | grep LOGNAME
```

And last but not least, remember that everything in Linux is just a file including the command that you have just executed:

```sh
cat /usr/bin/strings
```

**Note**: This article is not meant to insult anyone by any means; I just wanted to share it with everyone to clarify the situation with `.env` and give some tips on how to use them.

Have a lovely weekend, folks.

[Cover image](https://flic.kr/p/4yxQhX) by [Mike Souza](https://www.flickr.com/photos/zombiesquirrels), on [Flickr](https://www.flickr.com/).