DEV Community

Thiago Marinho
Thiago Marinho

Posted on

How to share envs in a monorepo with vite and nextjs apps

To share environment variables between two projects in a monorepo, with specific prefixes for each project, you can create a .env.shared file with common environment variables and then use scripts to create specific .env files for each project. Here's how to do that:

Create a .env.shared file at the root of the monorepo with the common environment variables:

SECRET_KEY=your_secret_key
API_URL=your_api_url
Enter fullscreen mode Exit fullscreen mode

Create a script to generate specific .env files for each project. In the example below, we will create a generate-env.js file at the root of the monorepo:

// generate-env.js
const fs = require('fs');
const path = require('path');

const envShared = path.join(__dirname, '.env.shared');
const envVite = path.join(__dirname, 'vite-project', '.env');
const envNext = path.join(__dirname, 'next-project', '.env');

const sharedVars = fs.readFileSync(envShared, 'utf-8').split('\n');

const viteVars = sharedVars.map((line) => {
  if (line.startsWith('SECRET_KEY') || line.startsWith('API_URL')) {
    return `VITE_PUBLIC_${line}`;
  }
  return line;
});

const nextVars = sharedVars.map((line) => {
  if (line.startsWith('SECRET_KEY') || line.startsWith('API_URL')) {
    return `NEXT_PUBLIC_${line}`;
  }
  return line;
});

fs.writeFileSync(envVite, viteVars.join('\n'), 'utf-8');
fs.writeFileSync(envNext, nextVars.join('\n'), 'utf-8');
Enter fullscreen mode Exit fullscreen mode

Run the generate-env.js script to generate the specific .env files for each project:

node generate-env.js
Enter fullscreen mode Exit fullscreen mode

This will create an .env file in the vite-project folder with environment variables prefixed with VITE_PUBLIC_ and an .env file in the next-project folder with environment variables prefixed with NEXT_PUBLIC_.

Now, each project will have its own .env file with the correctly prefixed environment variables. Be sure to add the generated .env files to your .gitignore rules to prevent committing sensitive information to the repository.

Remember to run the generate-env.js script whenever you make changes to the .env.shared file to update the specific project .env files. You can also add this script as a step in your build or deployment process.

Top comments (7)

Collapse
 
tgmarinhodev profile image
Thiago Marinho

eu particularmente prefiro ter uma .env para todo no monorepo no root e fazer um link para cada projeto e repetir o mesmo valor para keys diferentes, se for o caso.
NEXT_PUBLIC_API=123
VITE_API=123
só vou separar isso no ambiente de prod para cada projeto
tres formas de resolver isso:
1 - 2 env
2 - iqual ao artigo
3 - usando prompts e separar os ambientes: npm: inquirer
yarn dev --mainnet --api=production --strapi=production --no-prompt

Collapse
 
tgmarinhodev profile image
Thiago Marinho

I like to use it

gen-env.sh


# In repository root
cd "$(dirname $0)/.."

cp -n .env.example .env && echo 'Generated: .env'
ln -sf "$(pwd)/.env" apps/vite/.env && echo 'Linked: apps/vite/.env'
ln -sf "$(pwd)/.env" apps/nextjs/.env && echo 'Linked: apps/nextjs/.env'
Enter fullscreen mode Exit fullscreen mode
Collapse
 
designly profile image
Jay @ Designly

Doesn't work on windows

Collapse
 
treipatru profile image
Andrei • Edited

Just use the dotenv-cli NPM package. Add it to your workspace then prepend dotenv to any script and it will have access to your root env file at runtime.
Works cross-platform too and you don't have to maintain another script if you prefer a dependency over that.

Collapse
 
tgmarinhodev profile image
Thiago Marinho

thank you for sharing!

Collapse
 
designly profile image
Jay @ Designly

here's the sh way:

#!/bin/sh

# Path to the .env.api and .env.common files
env_api="./env/.env.api"
env_common="./env/.env.common"

# Iterate over each directory in packages/*
for dir in packages/*; do
    # Extract just the directory name without path
    package_name=$(basename "$dir")

    # Check if $dir is a directory
    if [ -d "$dir" ]; then
        echo "Processing directory: $dir"

        # Switch case based on the directory name
        case "$package_name" in
            admin)
                echo "Creating env for admin package"
                cat "$env_common" > "${dir}/.env.local"
            ;;
            api)
                echo "Creating env for api package"
                cat "$env_common" "$env_api" > "${dir}/.env.local"
            ;;
            player)
                echo "Creating env for player package"
                cat "$env_common" > "${dir}/.env.local"
            ;;
            ui-common)
                echo "Creating env for ui-common package"
                cat "$env_common" > "${dir}/.env.local"
            ;;
        esac
    else
        echo "Skipping ${dir}, not a directory."
    fi
done

echo "All directories processed."
Enter fullscreen mode Exit fullscreen mode
Collapse
 
tgmarinhodev profile image
Thiago Marinho

Great! thank you for sharing!