PM2: Why Aren't My Environment Variables Being Set?


I recently ran into an issue when working on a deployment that ended up pretty clearly pointing to some issues with environment variables. The application is leveraging PM2. This is a really handy tool most of time time, but there is also a lot of hidden corners and black magic at play. This can make resolving some seemingly obvious issues really challenging. Let’s sort out this one.

The PM2 configuration file was in charge of making sure that our environment variables were inserted into the application via node_args: "-r dotenv/config. This is the recommended method when using the dotenv package and this is how to accomplish this via the PM2 config.

// Some things I commonly set along with our node_args
{
  ...
  autorestart: true,
  watch: false,
  ignore_watch: ["views", "node_modules", ".tmp", ".git"],
  max_memory_restart: "1G",
  merge_logs: true,
  log_date_format: "YYYY-MM-DD HH:mm:ss.SSS Z",
  instances: "max",
  node_args: "-r dotenv/config",
  ...
};

The code all looked correct. The environment variables were set on the box and the configuration code was in fact on the server.

The Solution

It’s possible to save a PM2 configuration. This is supposed to enable “respawning” of applications on the reboot of your server. This seems like a useful thing on the surface, but so far I haven’t seen the benefit. In fact, I’ve seen way more problems then benefits. What was happening is that the configuration change wasn’t actually being reflected or used. At least as far as PM2 was concerned. In the ~/.pm2 directory are some dump.\* files. These are what gets “saved” when a pm2 save is run. These files weren’t updating and only after a lot of investigating and doing a pm2 save --force would the environment variables be there.

Based on my experience I’d recommended that you just never use pm2 save or npm save --force. It’s not particularly useful and can create really tricky problems like this one. If you choose to go this route I’d also recommend making sure that the dump.\* files are deleted. This should be a one-time thing assuming you aren’t doing any saves. If you do find value in the save functionality leverage the pm2 save --force command to ensure your configuration changes are being reflected.