I ve setup a basic turborepo project and I want to share .env
variables across the all the apps and some of packages. If I set one .env
file in the root of project and how can all apps and packages access them. Or for my requirement do I need to set multiple .env
files in all apps and packages?
8 Answers
As of December'22, the recommended way of doing this as per the official turbo
docs is as follows:
cd root-directory-of-your-project
.npm add -D dotenv-cli
(or withpnpm
:pnpm add -D dotenv-cli -w
).- Create a
.env
file in the root directory of your project.- Add your
.env
to your project's root.gitignore
.
- Add your
- Add your variables to the newly created
.env
file.- If you are using
nextjs
remember to prefix your public variables withNEXT_PUBLIC_*
(example:NEXT_PUBLIC_GOOGLE_ANALYTICS_TOKEN=1234
).
- If you are using
- On your
turbo.json
file, add the variables on which eachpipeline
job depends.- Example:
{ "$schema": "https://turborepo.org/schema.json", "pipeline": { "dev:frontend": { "outputs": ["dist/**", ".next/**"], "env": ["NEXT_PUBLIC_GOOGLE_ANALYTICS_TOKEN"] }, "dev:backend": { "outputs": ["dist/**", ".next/**"], "env": ["DATABASE_URL"] } } }
- Restart your local development server. Try logging
process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_TOKEN
.
Once finished, the structure of the project should look similar to the following:
apps
backend <<< Your backend code. You don't need to keep any .env file here.
frontend <<< Your frontend code. You don't need to keep any .env file here.
package.json <<< Where you should install dotenv-cli as a dev dependency.
turbo.json <<< Where pipeline jobs and their dependencies on environment variables are specified.
.env <<< Where all your environment variables will be stored.
Following turbo docs - Using environment variables
Steps:
- Add dotenv-cli to the project root.
# Installs dotenv-cli in the root workspace
yarn add dotenv-cli --ignore-workspace-root-check
- Update the root script (what runs your project with turbo), in my case "dev"
"scripts": {
"dev": "dotenv -- turbo run dev",
...
}
you may leave the turbo default globalDependencies setup in turbo.json
"globalDependencies": ["**/.env.*local"]
Optional:
- If you have a CRA, create a .env.local in the CRA app root and expand the variable
in workspace root .env:
VARIABLE=value
in CRA root .env.local:
REACT_APP_VARIABLE=${VARIABLE}
Restart server.
To load the env variables from .env into the process env you can use https://www.npmjs.com/package/dotenv.
Then to share the env variables in your monorepo :
In each workspace/app add require('dotenv').config({path: /custom/path/to/.env})
(assuming common js module resolution here) as early as possible as per docs (meaning e.g. for a next js app in next.config.js), where /custom/path/to/.env
would be the relative path to your root .env (e.g. two folders up:../../.env
)
-
This won't work for shared workspace libraries though... as the relative path will be changed compared to the library files.– SpockCommented Jun 20, 2023 at 20:59
You can specify the globalDependencies
option in your turbo config or use the --global-deps
CLI flag.
{
// ... rest of the turbo config
globalDependencies: ['.env']
}
or
turbo run build --global-deps=".env.*"
References from docs:
https://turborepo.org/docs/reference/configuration#globaldependencies https://turborepo.org/docs/reference/command-line-reference#--global-deps
-
13
The globalDependencies
mentioned on the other answers is like the docs says:
A list of file globs for implicit global hash dependencies. The contents of these files will be included in the global hashing algorithm and affect the hashes of all tasks. This is useful for busting the cache based on .env files (not in Git) or any root level file that impacts workspace tasks
So, it's needed to cache that specific task, build etc... on turbo caching but not to load it on the application.
To load env variables from a centralized .env
file into multiple processes, you may use my new package https://www.npmjs.com/package/dotenv-mono, which was designed specifically for this purpose.
Install dotenv-mono (
yarn add dotenv-mono
ornpm install dotenv-mono --save
)Place your
.env
file in the root of your projectThen load it as follows on your packages/applications init file (
index.{js,ts}
,next.config.js
, etc...):require("dotenv-mono").load();
Check out the github page for more documentation https://github.com/marcocesarato/dotenv-mono
This package @dotenv-run/cli might help.
.env.* files
can be defined in the root workspace and overriden by each application
/workspace
apps
frontend1
.env.local # API_USERS=http://localhost:3001/users
src/
.env.dev # API_BASE=https://dotenv-run.dev
.env.prod # API_BASE=https://dotenv-run.app
.env # API_USERS=$API_BASE/api/v1/users API_AUTH=https://$API_BASE/auth
package.json
turbo.json
$> cd /workspace/apps/frontend1
$> NODE_ENV=dev dotenv-run -- bash -c 'printf "✨API_USERS $API_USERS\n✨ API_AUTH $API_AUTH"'
✔ /workspace/apps/frontend1/.env.local
✔ /workspace/.env.dev
✔ /workspace/.env
✨ API_USERS http://localhost:3001/users
✨ API_AUTH https://dotenv-run.dev/api/v1/auth
- Add dotenv-cli, in your project root
npm add -D dotenv-cli
- update script
"dev": "dotenv -- turbo run dev",
- Add .env file to the project root
From Docs
I've found this approach to work.
- Install
env-cmd
(yarn install env-cmd
) - Make a shell script called
turbo-run.sh
that does the following:
# remember to use direct paths to files because yarn has a habit
# of stripping out `--` flags (which are used in turborepo to pass
# in extra args to turbo commands)
./node_modules/.bin/env-cmd \
--file $ENV_FILE \
./node_modules/.bin/turbo run \
$@
(also chmod +x
it so that you can execute it)
- Then setup your package.json scripts to have a
turbo-run
command that calls./turbo-run.sh
- Now you can do
yarn turbo-run foo
and ensure that it always callsenv-cmd
with the appropriate ENV_FILE file.