Magically use environment variables without a .env file
Tags: webdev, javascript, python, devops
Published: 2023-05-18 13:51:26


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfxo86fjq18pfl230lqu.png)

TLDR: You can build or use a pre-made CLI together with your application's start command to inject environment variables for local development and avoid using a `.env` file altogether.

Recently, I wrote about fetching environment variables for applications so teams always have access to the right variables. The method was simple: store environment variables in a secret management platform, then have the application fetch them back and cache them at runtime. This, however, came with a nuance of having to manage yet another token to fetch these variables.

In this article, however, I discuss an enhanced approach specifically for local development to inject environment variables into an application without needing a `.env` file at all.

## It sucks to fetch environment variables back for an application if the method still requires managing one environment variable

This is a common complaint and debate amongst developers considering to use a secret management platform to store their environment variables only to find out that they still need to manage a token to gain access to the platform.

While the approach of storing a token in a `.env` file and using it to fetch back environment variables tamed secret sprawl, it did little to improve on the security front. After all, you could still leak the token to source control and, if not revoked, bad actors could use it to access your environment variables.

I'm glad to say, however, that you can use a secret management platform and fetch environment variables back without needing to store another proxy token. Here's how:

## You can inject environment variables into your application using a CLI

Let me explain.

It turns out that your application running in local development is just a process and it's possible to pass environment variables into that process as it starts up. This means that you can build a platform-agnostic CLI to fetch back environment variables from a centralized source and wrap it around your application's start command. Couple the CLI with authentication logic and proper credential storage on your system and you can have a secure workflow that pulls and injects environment variables into your local development process.

Moving forward, members of your team only need to install the CLI onto their machine, authenticate with the secret management platform via the CLI, and start up their application via CLI with environment variables injected - Wizardry.

## That's enough, show me your recommendation, gimme the code

While you can code the CLI yourself and connect it to an existing secret management platform, I wouldn't recommended it for most developers since this isn't a quick endeavor. Instead, I'm going to be using the [Infisical CLI](https://infisical.com/docs/cli/overview) to pull and inject environment variables in local development from [Infisical](https://github.com/Infisical/infisical), a popular open-source, end-to-end encrypted secret management platform that you can store environment variables with.

It's worth noting that [Infisical](https://github.com/Infisical/infisical) is self-hostable on your own infrastructure and [well-documented](https://infisical.com/docs/documentation/getting-started/introduction).


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vm3j6zaldok3sszvqova.png)

## Getting started

Before we can fetch environment variables back into your application, you need to add them to a project in [Infisical Cloud](https://app.infisical.com/) or in a [self-hosted instance of Infisical](https://infisical.com/docs/self-hosting/overview).

Okay, let's get started.

First, install the CLI onto your machine.

**MacOS (using brew):**

```bash
brew install infisical/get-cli/infisical
```

**Windows (using scoop):**

```bash
scoop bucket add org https://github.com/Infisical/scoop-infisical.git
```
```bash
scoop install infisical
```

**Arch Linux (using yay):**

```bash
yay -S infisical-bin
```

Check out the [documentation](https://infisical.com/docs/cli/overview) for more installation options like Redhat/CentOS/Amazon and Debian/Ubuntu if your system is missing above.

Next, authenticate with Infisical using the CLI:

```bash
infisical login
```

This command authenticates the CLI with Infisical Cloud or your self-hosted instance and stores credentials in your system keyring. 

Next, navigate to the root of your project and run the initialization command:

```bash
infisical init
```

This command creates a `infisical.json` file holding a reference to your project in Infisical Cloud or self-hosted instance; the file can be committed to source control.

Finally, start your application in local development with the help of the CLI:

```bash
infisical run -- <your application start command>
```

If you're using a self-hosted instance of [Infisical](https://github.com/Infisical/infisical), you can run this command instead:

```bash
infisical --domain="https://your-self-hosted-infisical.com/api" run -- <your application start command>
```

This command fetches environment variables back from the development environment of your project in Infisical and starts up your application with the variables injected. The environment variables become available in the application environment. For example, they're accessible on `process.env` in Node.js or on `os.environ` in Python.

While the CLI comes with a few helpful subcommands and flags that you can read more about in the documentation, in practice, the basic command above is all you need 99% of the time.

Here're some examples for common frameworks:

```bash
# example with node
infisical run -- node index.js

# example with node (nodemon)
infisical run -- nodemon index.js

# example with Next.js
infisical run -- npm run dev

# example with flask
infisical run -- flask run

# example with django
infisical run -- python manage.py runserver

# example with laravel
infisical run -- php artisan serve

# example with rails
infisical run -- bin/rails server

# example with .NET
infisical run -- dotnet run
```

That's it!

Now you can use environment variables in local development without a .env file and feel confident that your team will not leak anything to source control. You're now also able to view all the environment variables for your application from one central place and avoid any missing environment variables.

## How do I trust a secret manager?

I'm including this section because it has been helpful to developers in past articles.

Adopting a secret manager can be daunting at first and rightfully so. You have to trust that the solution you're working with is secure, that the vendor won't view or tamper with your data, and that the underlying infrastructure will work and deliver environment variables reliably when needed. There is, however, a right tool for every task and using dedicated tooling to manage environment variables is surely better than any manual process that's either not efficient or prone to error.

The analogy I like to use is password managers like 1Password and Bitwarden. Before using one, I was content with managing dozens of passwords manually and occasionally forgetting them. The minute I started to face **password sprawl**, however, I was compelled to upgrade my workflow and sign up for a password manager. 

Similarly, in the realm of secret managers, when you're a solo developer, you can use manual approaches to store your environment variables. The minute, however, you start to scale to above five engineers, you start to face **secret sprawl** and that's where a secret management solution can really help. My suggestions for selecting one:

- Pick a solution that's either open source or made by the big cloud providers; it will be more resilient that way and you can inspect and, in the open source case, make changes to the code if needed.

- Pick something that provides a good developer experience for the size of your team. If you have site reliability engineers and teams for process, you can afford to go with more complex tools. Otherwise, if you're a smaller team, go frictionless and focus on building the rest of your application.

## Conclusion

We developers often debate the practicality of using a secret management platform when faced with the need to yet manage another token to access environment variables or secrets. This unfortunately comes off as counterintuitive to many developers who then hesitate on adopting a secret management solution.

In this article, however, I demonstrate a workflow using a CLI that fetches environment variables and injects them into any application upon starting up; the method avoids  storing any proxy token in a .env file. With this CLI approach, development teams stop risking leaking environment variables to source control by not storing any variables in plaintext in .env files on their machines.