Use dotenvx with Nx

Use dotenvx with Nx

Initial setup

Create a new monorepo.

npx create-nx-workspace --preset=express

This will create a handful of files and a couple workspaces (apps).

$ ls -1
README.md
apps/
jest.config.ts
jest.preset.js
node_modules/
nx.json
package-lock.json
package.json
tsconfig.base.json

Edit apps/app/src/main.ts to include process.env.HELLO – to say 'Hello World'.

apps/app/src/main.ts

import express from 'express';
import * as path from 'path';

const app = express();

app.use('/assets', express.static(path.join(__dirname, 'assets')));

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

const port = process.env.PORT || 3333;
const server = app.listen(port, () => {
  console.log(`Listening at http://localhost:${port}/`);
});
server.on('error', console.error);

Run dotenvx

Install dotenvx.

brew install dotenvx/brew/dotenvx

see other installation options

Create a .env file under apps/app.

apps/app/.env

# apps/app/.env
HELLO="World"

Run nx serve prefaced by dotenvx.

$ dotenvx run --env-file=apps/app/.env -- npx nx serve app

[[email protected]] injecting env (1) from apps/app/.env

> nx run app:serve:development
...

Visit localhost:3333.

localhost:3333

Your app will say Hello World. The values from your .env file were successfully injected into your env.

Add production environment

Create a .env.production file under apps/app.

apps/app/.env.production

# apps/app/.env.production
HELLO="production"

Modify your dotenvx run command to use the .env.production file.

$ dotenvx run --env-file=apps/app/.env.production -- npx nx serve app

[[email protected]] injecting env (1) from apps/app/.env.production

> nx run app:serve:development
...
localhost:3333

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

Encrypt secrets

Use dotenvx to encrypt your apps/app secrets.

dotenvx encrypt apps/app

Also run dotenvx gitignore to make sure your .env.keys file is gitignored

dotenvx gitnore

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 simulate production by using the DOTENV_KEY.

Set DOTENV_KEY

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

DOTENV_KEY='dotenv://:key_10283719af6a30ef49050048617f4fea10c23a38021fbebeb9fd858caa01852e@dotenvx.com/vault/.env.vault?environment=production' npx nx serve app

Your script starts and env is successfully injected using the encrypted contents of .env.vault.

[[email protected]][INFO] Loading env from encrypted .env.vault
Listening at http://localhost:3333/

Visit your url and it says Hello production.

localhost:3333

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.

apps/app/.env.production

# apps/app/.env.production
HELLO="Mot"

Re-encrypt it.

dotenvx encrypt apps/app

Commit .env.vault safely to code and re-serve the app.