Handling Env Files In The Latest Node.JS
Published: 2024-03-01 13:27:06

by [Nathanael Adam](https://blog.openreplay.com/authors/nathanael-adam)


<blockquote><em>
The Node.JS team released several versions recently; among these is the v20.6.0, which comes with built-in support for env files. In this article, you’ll learn about env files, how they were handled before, and how you can now handle env files in the latest releases.
</em></blockquote>


<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>


Environment files ("env files") safely store environment variables, which serve a purpose in your code but have to be kept separate from your code. 

These variables could be API keys, database configurations or some other secret that should be hidden from the user.

These variables are stored in key-value pairs. The code below is an example of a key-value pair.  
```javascript
MY_SECRET_KEY=my-secret-value
```
In this example, `MY_SECRET_KEY` is the key while `my-secret-value` represents the value.

To use an environment variable, the key is specified in the code while the value is safely hidden in an env file. The value is then accessed at runtime using the `process.env` variable.

<div class="alert alert-block alert-info">
<b>Runtime:</b> Runtime refers to the period within which your code executes in an environment, from when it starts running to when it stops. The runtime environment for Javascript is Node.JS.
</div>

Env files are important because they keep env variables and other private information from falling into the wrong hands while providing easy access when the variables are needed.

Interestingly, [Node.JS](https://nodejs.org/en) doesn’t have built-in support for env files in Node.JS versions earlier than [v20.6.0](https://nodejs.org/en/blog/release/v20.6.0). This means projects using those Node versions would need to handle env files using other means.

## How env files were handled with Node.JS
Before the recent Node.JS releases, env files were handled using third-party packages. A prevalent package to handle env files is [the `dotenv` package](https://github.com/motdotla/dotenv#readme) - a npm package that loads environment variables from env files in your project. As of writing, the `dotenv` package has over 35m weekly downloads on [npm](https://www.npmjs.com/) - showing its popularity and reliability regarding handling env files.

To load env files in your Node.JS project using the `dotenv` package, you would need to do the following things:

1. Install the `dotenv` package using
```shell
npm install dotenv
```
or if you use yarn
```shell
yarn install dotenv
```
2. Create a `.env` file and add your variable(s)
```
YOUR_SECRET_KEY=your-secret-value
```
3. Import the package at the top level of your Node.JS projects and call its `config()` function
```javascript
require("dotenv").config();
```
4. Load the variable into your code using
```
process.env.YOUR_KEY
```
Now, [Node v20.6.0](https://nodejs.org/en/blog/release/v20.6.0) and above will load env variables from env files without needing a different package.
## Node.JS new handling of env files
Handling env files in the new Node.JS releases is similar to the `dotenv` package, except you don't need to import any package. You just need to do the following: 

1. Add a `.env` file to your folder and define your key-value pair(s). 
2. Use `process.env` to access the variable in your env file.
3. Start or restart your Node.JS application using the `node` command and the `--env-file` flag.

A necessary prerequisite for these actions is to have the appropriate version of Node.JS installed on your device, and you can check the Node.JS version you have by typing `node -v` in your terminal. 

If you have a Node version earlier than v20.6.0, you must upgrade it.

You can upgrade your Node version using either the [nvm](https://github.com/nvm-sh/nvm) package or by downloading and installing a new Node.JS version from the [Node.JS website](https://nodejs.org/en).

## Using env files in a Node.JS app
In this section, we'll connect to a [Mongodb](https://www.mongodb.com/) database from a Node.JS application and use an env file to store our database connection string.

### Setting up a Node.JS server
First, we need a Node.JS server:
1. Start a new Node.JS application using 
```
npm init -y
``` 
This will create a default `package.json` file in your directory.

2. Create an `index.js` file in your root folder; your code will be in this file. Your folder structure should look like the one below
```
|-- index.js
|-- package.json
```
Now add this code to your `index.js` file
```javascript
//index.js
const http = require("node:http");
const hostname = "127.0.0.1";
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader("Content-Type", "text/plain");
  res.end("Hello world");
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```
The code above creates a basic Node.JS server using the `http` protocol. It uses the `http` protocol to create a server and serve a "Hello world" response on `port 3000`.


<CTA_Middle_Frameworks />



### Setting up the Mongo database
Install `MongoDB` using,
```
npm install mongodb
```
then, at the top level of the `index.js` file import `MongoClient` and `ServerApiVersion.`
```javascript
const { MongoClient, ServerApiVersion } = require('mongodb');
```
Next, add the Mongo boilerplate for connecting to your database
```javascript
const client = new MongoClient(uri, {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  },
});

async function run() {
  try {
    // Connect the client to the server (optional starting in v4.7)
    await client.connect();
    // Send a ping to confirm a successful connection
    await client.db("admin").command({ ping: 1 });
    console.log(
      "Pinged your deployment. You successfully connected to MongoDB!",
    );
  } finally {
    // Ensures that the client will close when you finish/error
    await client.close();
  }
}
run().catch(console.dir);
```
### Using environment variables
To connect to `MongoDB` you will need a connection string. You can get this string when you create an account and a database for your project.

Below is an example of a connection string.
```
mongodb+srv://<YOUR_NAME>:<YOUR_PROJECT_NAME>.mongodb.net/?retryWrites=true&w=majority
```
This string grants read/write access to your database so it's something you can not expose in your code.

You can store this connection string by doing the following,

1. Create a `.env` file at the root of your folder

2. In the `.env` file, add your secret; the secret for this example will be the `MongoDB` connection string.
```
MONGO_DB_URI = YOUR_MONGO_STRING_HERE
```
3. Create a `.gitignore` file in the root of your project, giving you a folder structure like the one below
```
|-- node_modules
|-- index.js
|-- package-lock.json
|-- package.json
|-- .env
|-- .gitignore
``` 
A `gitignore` file keeps the specified file from getting pushed to [Github](https://www.github.com). Inside the `.gitignore` file, you just need to type `.env`, and your `.env` file will be kept from Github.

4. Now, go to the `index.js` file and add this just below the imports
```javascript
const uri = `${process.env.MONGO_DB_URI}`;
```
Your connection string has now been assigned to the variable `URI,` which gives `MongoClient` access to your database. You don't need to do anything else since `uri` has already been used in `MongoClient` in the boilerplate
```javascript
const client = new MongoClient(uri, {
  //rest of the code here
});
```
### Starting the server
Now here's something interesting, if you start the server using `node index.js` you will get an error in your console
```
MongoParseError: Invalid scheme, expected connection string to start with "mongodb://" 
or "mongodb+srv://"
```
This error is because you haven't used the `-env-file` flag to tell Node to watch the `.env` file where you have the connection string.

So, to properly restart the server you need to use, 
```
node --env-file=.env index.js
```
Now, Node knows to watch the `.env` file for environment variables, and `process.env` makes the env variable available at runtime.

If you check your console, you should see,
```
Server running at http://127.0.0.1:3000/
```
After a second or two you should also see a database connection success message.
```
Pinged your deployment. You successfully connected to MongoDB!
```
Now your server is securely connected to your database without needing a third-party package like dotenv.

### Loading multiple env files
There may be times when you'll have different env files for a production environment and a local environment. This means you'll have two env files in a project, a `.env` file, and a `.env.local` file.

Node allows watching multiple env files, so if you want to watch two env files like `.env.local` and `.env` together, you just need to do it like so,
```
node --env-file=.env.local --env-file=.env index.js
```
Note that if you have environment variables with the same key in both env files, the variable in the latter `env` file will override the former. Here's a basic example:
```
.env.local
SECRET_KEY=a-secret-key
```
```
.env
SECRET_KEY=another-secret-key
```
The two env files have the same key, `SECRET_KEY`; if you load them together using the command above, Node.JS will not treat them as separate env variables. Instead, the `env` variable for `.env` will override the variable for `.env.local`.

If you change the order and type it like,
```
node --env-file=.env --env-file=.env.local index.js
```
The variable in `.env.local` will override that of the `.env` file.

While this can be frustrating if you type the flags in an incorrect order, it could also be helpful if you cannot or do not want to change the secrets in a certain env file, and you need to load other variables in that file. This way you can override a single variable without changing the file.

## Conclusion
This article has talked about what env files are, how env files used to be handled in Node.JS using the `dotenv` package, and how the Node.JS new releases now support env files. 

You can check the Node.JS [release docs](https://nodejs.org/en/about/previous-releases) to see other features that came out in the recent releases and how they can help you build better Node.JS applications.