Use dotenvx with Turborepo

Use dotenvx with Turborepo

Initial setup

Create a new monorepo.

npx create-turbo@latest

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

$ ls -1
README.md
apps/
node_modules/
package-lock.json
package.json
packages/
turbo.json

Edit apps/web/app/page.tsx to include process.env.HELLO – to say 'Hello World'.

apps/web/app/page.tsx

export default function Page() {
  return (
    <>
      Hello {process.env.HELLO}
    </>
  );
}

Declare the apps/web environment variable in turbo.json by adding a web#build configuration under the pipeline configuration key.

turbo.json

  ...
  "pipeline": {
    ...
    "web#build": {
      "dependsOn": [
        "^build"
      ],
      "env": [
        "HELLO"
      ]
    },
    ...

Run dotenvx

Install dotenvx under apps/web

cd apps/web
npm install @dotenvx/dotenvx --save
cd ../..

Create a .env file under apps/web.

apps/web/.env

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

Adjust your apps/web/package.json scripts to inject your env using dotenvx.

apps/web/package.json

...
"scripts": {
  "dotenvx": "dotenvx",
  "build": "dotenvx run -- turbo build",
  "dev": "dotenvx run -- turbo dev",
  "lint": "dotenvx run -- turbo lint",
  "format": "prettier --write \"**/*.{ts,tsx,md}\""
},

Try running it locally.

$ npm run dev
web:dev: [[email protected]] injecting env (1) from .env
docs:dev: - ready started server on 0.0.0.0:3001, url: http://localhost:3001
web:dev: - ready started server on 0.0.0.0:3000, url: http://localhost:3000

Visit localhost:3000.

localhost:3000

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/web.

apps/web/.env.production

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

Encrypt production

dotenvx encrypt -f apps/web/.env.production

Your .env.production file is now encrypted, and you have a .env.keys file.

apps/web/.env.production

#/-------------------[DOTENV_PUBLIC_KEY]--------------------/
#/            public-key encryption for .env files          /
#/       [how it works](https://dotenvx.com/encryption)     /
#/----------------------------------------------------------/
DOTENV_PUBLIC_KEY_PRODUCTION="025a54defaeff32caa2bbe60537b88b5b89716eade6df08418d7a68f5c4f742be6"

# .env.production
HELLO="encrypted:BD+uttK9iBuXnfx6HukDK06IGk0pQARwivtxM+ZiePvhRxHyQL3UD0sf0ayLw/P5Y/BED//zRiTlUf6nENuu7QhNJ24g3uADfrDfhvYi/MOHjmfKyRiu+yOxSw6e+c0yRNukS+n8SxONnec="

apps/web/.env.keys

#/------------------!DOTENV_PRIVATE_KEYS!-------------------/
#/ private decryption keys. DO NOT commit to source control /
#/     [how it works](https://dotenvx.com/encryption)       /
#/----------------------------------------------------------/

# .env.production
DOTENV_PRIVATE_KEY_PRODUCTION="424d0ea072eb17c6bee9b4b42ff6333513cf128ea3d5d60ccf79246ca7c3f786"

We're ready to inject the encrypted .env.production secrets into the app on boot.

Set decryption key

Set DOTENV_PRIVATE_KEY_PRODUCTION using the production key in your apps/web/.env.keys file.

DOTENV_PRIVATE_KEY_PRODUCTION="424d0ea072eb17c6bee9b4b42ff6333513cf128ea3d5d60ccf79246ca7c3f786" npm run dev

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

web:dev: [[email protected]] injecting env (1) from .env
docs:dev: - ready started server on 0.0.0.0:3001, url: http://localhost:3001
web:dev: - ready started server on 0.0.0.0:3000, url: http://localhost:3000

Visit your url and it says Hello production.

localhost:3000

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.

npm run dotenvx -- set HELLO Mot -f .env.production

Commit .env.production safely to code and redeploy.