Use dotenvx with Heroku

Use dotenvx with Heroku

Initial setup

Add a Procfile to run your app.

# Procfile
web: node index.js

Install the necessary web server libraries in the language of your choice.

npm install express --save

Create a simple Hello World program.

// index.js
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000

app.get('/', (req, res) => {
  res.send(`Hello ${process.env.HELLO || ''}`)
})

app.listen(PORT, () => {
  console.log(`Server running on port:${PORT}`)
})

Commit to code and push to Heroku.

git commit -am "initial commit"
heroku create
git push heroku
yourapp.herokuapp.com

Once deployed, your app will say 'Hello [blank]' as it doesn't have a way to access the environment variable yet. Let's do that next.

Run dotenvx

Install dotenvx.

# install with Homebrew and then use the dotenvx command
brew install dotenvx/brew/dotenvx
dotenvx help

Create a .env file in the root of your project.

.env

# .env
HELLO="World"

Inject your env using dotenvx.

dotenvx run -- node index.js
localhost:$PORT

Your app will say Hello World. The values from your .env file were successfully injected into your env. That covers local development. Let's solve for production next.

Add production environment

Create a .env.production file in the root of your project.

.env.production

# .env.production
HELLO="production"

Use dotenvx to load your .env.production file.

dotenvx run --env-file=.env.production -- node index.js
localhost:$PORT

Your app will say Hello production, simulating production. Solid. Let's encrypt your secrets next.

Encrypt secrets

Use dotenvx to encrypt your secrets.

dotenvx encrypt

This generates a .env.vault and .env.keys file.

.env.vault

#/-------------------.env.vault---------------------/
#/         cloud-agnostic vaulting standard         /
#/   [how it works](https://dotenv.org/env-vault)   /
#/--------------------------------------------------/

# development
DOTENV_VAULT_DEVELOPMENT="V4NYVn0Pow6Uf2ez2mbHEzTrYURloHL6VDAFRLqnQBppA/OmHI5x5AXoxCMVor7wOg=="

# production
DOTENV_VAULT_PRODUCTION="YZkhtbh1IlzBgIamAAsG5nzGPfH6p8Zbuj9egXoziviVu/eYIyNjJWtIYyhiW/vHhFbqbsvo5+P9b27OC6ZC7qU="

The .env.vault file contains encrypted (AES-256-GCM) versions of your secrets, and the .env.keys file contains the decryption keys.

.env.keys

#/!!!!!!!!!!!!!!!!!!!.env.keys!!!!!!!!!!!!!!!!!!!!!!/
#/   DOTENV_KEYs. DO NOT commit to source control   /
#/   [how it works](https://dotenv.org/env-keys)    /
#/--------------------------------------------------/
DOTENV_KEY_DEVELOPMENT="dotenv://:key_e507c60efa8841d8d5bbb85bd701ee92406cf3b06506d1d80f1553c2a72791e4@dotenvx.com/vault/.env.vault?environment=development"
DOTENV_KEY_PRODUCTION="dotenv://:key_10283719af6a30ef49050048617f4fea10c23a38021fbebeb9fd858caa01852e@dotenvx.com/vault/.env.vault?environment=production"

We're ready to add dotenvx to Heroku.

Add dotenvx buildpack

Install the dotenvx buildpack.

heroku buildpacks:add https://github.com/dotenvx/heroku-buildpack-dotenvx

Update your Procfile to use dotenvx.

# Procfile
web: dotenvx run -- node index.js

Redeploy to Heroku.

git push heroku
$ heroku logs --tail
heroku[web.1]: Starting process with command `dotenvx run -- node index.js`
app[web.1]: [[email protected]] missing .env file (/app/.env)
app[web.1]: ? in development: add one with [echo "HELLO=World" > .env] and re-run [dotenvx run -- node index.js]
app[web.1]: ? for production: set [DOTENV_KEY] on your server and re-deploy

The logs tell us missing .env file. This is expected, as we don't want to commit .env to code. It also tells us, for production, that we should set DOTENV_KEY. That is what we want to do. Let's do that next.

Set DOTENV_KEY

Set DOTENV_KEY on Heroku using the production key in your .env.keys file.

heroku config:set DOTENV_KEY='dotenv://:key_10283719af6a30ef49050048617f4fea10c23a38021fbebeb9fd858caa01852e@dotenvx.com/vault/.env.vault?environment=production'
www.heroku.com

Your app restarts and env is successfully injected using the encrypted contents of .env.vault.

heroku[web.1]: Starting process with command `dotenvx run -- node index.js`
app[web.1]: [[email protected]] injecting env (1) from encrypted .env.vault
app[web.1]: Server running on port:7521/

Visit your url and it says Hello production.

yourapp.herokuapp.com

Great job! That's pretty much it. See the bonus section(s) below to go a little deeper.


Bonus

Try changing the value of .env.production to your name.

.env.production

# .env.production
HELLO="Mot"

Re-encrypt it.

dotenvx encrypt

Commit .env.vault safely to code and redeploy.

git commit -am "update production secret"
git push heroku