Accessing Environment Variables in an Easier Way
Tags: javascript, node, express, serverside
Published: 2021-06-15 01:45:26

---
title: Accessing Environment Variables in an Easier Way
published: true
description: Read why you should consider consolidating environment variable access to a single file
tags: javascript, node, express, serverside
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/borhkbqjo8ezq8dzgw2i.png
---

In server-side development, it's extremely common to access variables from the execution environment. 

In this post, I hope to convince you to consolidate access of these variables into one single-file (__or__ a more structured way of accessing these values) to make it easier to refactor, maintain, and update as your project grows.

```ts
// Logging to console the stage we're on
console.log(`This is the ${process.env.NODE_ENV}`);
```

## Why is it useful to access variables from the environment?

I won't dive too much into the __why__ of this, but you typically access sensitive values via this way, such as
- API keys and secrets
- Application identifiers
- Stage of the environment (looking at you `NODE_ENV`)
- JSON Web Token key
- Database access credentials
- other top-secret values of this nature

These are values that you **do not want committed to a version control system like GitHub** and so you keep them out of there for security purposes. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8s6vnqmvq7qdx13kyqs.png)
 
You might also keep these out of there because these vary from stage to stage, and thus makes no sense to keep in GitHub. 

So, getting them during runtime of the program it is! 😃

## What's the issue with process.env?

In your own projects, you might be accessing environment variables through `process.env.MY_VARIABLE`. This is great! It's fine, and it works.

But is it optimal? 

Imagine you have two files that access the same environment variable, some sort of API key

```ts
// Usage 1
axios({
  url: `${process.env.CMS_URL}/random-endpoint-1`/v1/random-endpoint-1`
  header: `Bearer ${process.env.MY_API_KEY}`
});

// ...

// Usage 2
axios({
  url: `${process.env.CMS_URL}/random-endpoint-1`/v1/random-endpoint-2`
  header: `Bearer ${process.env.MY_API_KEY}`
});

```

Both of these files are accessing the same API key from the environment directly. Now imagine your projects expands in scale and you have many more instances where this API key needs to be accessed.

See the problem that might occur? You now would `process.env.MY_API_KEY` littered throughout your project.

What if you need to change the environment variable from `process.env.MY_API_KEY` to `process.env.TWITTER_API_KEY`? 

- Yes, you can easily rename all instances (using a powerful editor like VS Code). But this is going to cause a pretty large commit created for this simple change.

What if you have a plethora environment variables, and you want to group them? Like API credentials, database credentials, etc.?

- There's no way to do this with the normal `process.env.XXX_YYY` usage. Everything is at the same level and there's no grouping them.

What if you want to add context to each environment variable, so engineers can understand what purpose they serve?

- You can do this in your `.env.template` file as single-line comments, but this won't show up in the IDE as a hint or documentation for your team members.


## How should we be accessing the environment variables?

I won't say you 100% definitively, absolutely, should follow my advice. But I think it can help prevent the above shortcomings (and also __add to__ your current environment variable usage).


**Add a `config.js` or `config.ts` file!**

What do I mean? 

I mean consolidate access of environment variables from using `process.env.XXX_YYY` everywhere, to just accessing it once! Through a single file(s)!

It can look something like

```ts
export const Config = {
    cmsUrl: process.env.CMS_URL,

    dbHost: process.env.DB_HOST,
    dbUser: process.env.DB_USER,
    dbPassword: process.env.DB_PASSWORD,
    dbName: process.env.DB_NAME,

    jwtSecret: process.env.ZEROCHASS_SECRET,

    awsRegion: process.env.AWS_REGION,
    awsBucket: process.env.AWS_BUCKET,

    twitterApiKey: process.env.TWITTER_API_KEY,
}
```

Now, whenever I want to access __any__ of these environment variables, I can do so by importing this file. 

No more having to write `process.env.MY_VARIABLE` over and over!

My above example with axios becomes this

```ts
import { Config } from './config';

// Usage 1
axios({
  url: `${Config.cmsUrl}/random-endpoint-1`
  header: `Bearer ${Config.twitterApiKey}`
});

// ...

// Usage 2
axios({
  url: `${Config.cmsUrl}/random-endpoint-2`
  header: `Bearer ${Config.twitterApiKey}`
});

```

If I ever need to change the environment variable that the Twitter API key was stored in, I don't have to change a zillion files, I just change it here in `config.ts`!

If I need to add documentation and group items, I can easily add it here.

```ts
export const Config = {

    general: {

      /** The URL for our Craft environment */
      cmsUrl: process.env.NEXT_PUBLIC_CRAFT_CMS_URL,

      jwtSecret: process.env.ZEROCHASS_SECRET,

      /** The stage we're on, should be QA/Dev/Prod */
      nodeEnv: process.env.NODE_ENV,
    },

    database: {
      host: process.env.DB_HOST,
      user: process.env.DB_USER,
      password: process.env.DB_PASSWORD,
      name: process.env.DB_NAME,
    },

    aws: {
      region: process.env.AWS_REGION,
      bucket: process.env.AWS_BUCKET,
    },

    twitter: {

      /** API v1 URL for Twitter */
      apiUrl: process.env.TWITTER_API_URL,

      /** API key for our Twitter app */
      apiKey: process.env.TWITTER_API_KEY,
    },
}
```

And anyone who imports this file will get all that context, including the code hints on hover!

Hopefully this short post has given you some insight on how you might rethink your environment variable usage. You can even throw in some value-validation here, but I won't cover that here.

Let me know your thoughts!