DEV Community

gortron
gortron

Posted on

Environment Variables with pm2: The Right Way

Introduction

This post is meant to support anyone who is setting up environment variables for a Node.js daemon that they will manage with pm2. Specifically, this post will show you how to handle NODE_ENV for development and production settings for pm2.

There are multiple ways to handle environment variables for a pm2 daemon.
1) Some deployment tools, like Heroku or Netlify, let you set environment variables.
2) You can set them in your CLI.
3) You can use a pm2 ecosystem.yml file.

There are trade-offs between all of these approaches. The first option forces you to navigate a deployment tool's interface to figure out any bugs relating to environment variables.

The second approach makes it easier to debug. You might implement it with something like this, in the scripts section of your package.json:

"scripts": {
  "start": "NODE_ENV=production && pm2 start app.js",
  "dev": "NODE_ENV=development && pm2 start app.js"
}

While this approach is viable, to my tastes it feels "hacky". It does the immediate job of setting one environment variable, but what if you wanted to set more environment variables? Maybe you would write a set_env_var.sh script and invoke it in your package.json script, but then you would have to go to that shell script to debug any issues.

pm2 provides a preferred way to handle environment variables: an ecosystem file.

Solution

Compare this ecosystem.yml file below with the package.json snippet above:

apps:
  - script: ./app.js
    name: "app"
    env:
      NODE_ENV: development
    env_production:
      NODE_ENV: production

It would be far easier to add environment variables, here. And, better still, you're clearly communicating your intent to your collaborators: this file is where we handle environment variables for our pm2 daemon.

You complete the solution by adding something like the following to your package.json:

"scripts": {
  "start": "pm2 restart ecosystem.yml --env production",
  "dev": "pm2 restart ecosystem.yml --env development"
}

Similar to the first package.json scripts, these scripts will start (or restart an existing) pm2 process, and update the environment for that process to include the variables you declared in your ecosystem.yml file.

This is a useful pattern, when setting up dev ops for a pm2 micro service. Consider the following snippet from app.js:

const TOKEN =
    process.env.NODE_ENV === "production"
      ? process.env.PROD_TOKEN
      : process.env.DEV_TOKEN;

If you call yarn start, you will re/start a pm2 process with a token designated for production; if you call yarn dev, you will re/start a pm2 process with a token designated for development.

Conclusion

I hope this guide was useful for anyone getting started with pm2, and thinking through how to implement environment variables for their daemon. An example application that uses this pattern can be found on my GitHub.

Discussion (0)