Skip to content

Using with Monorepos

Envi is designed to work seamlessly with monorepos, capturing env files from all packages and services.

How It Works

When you run envi capture in a monorepo:

  1. Single configuration - All env files are stored in one MAML file
  2. Relative paths - File locations are preserved (e.g., packages/web/.env.local)
  3. Package-based naming - Uses root package.json name or folder name

Example Monorepo Structure

my-monorepo/
├── package.json              # name: "@myorg/monorepo"
├── .env
├── apps/
│   ├── web/
│   │   ├── .env.local
│   │   └── .env.production
│   └── api/
│       └── .env.development
├── packages/
│   └── core/
│       └── .env.test
└── services/
    ├── auth/
    │   └── .env
    └── notifications/
        └── .env.production

Capturing

From the monorepo root:

bash
$ cd my-monorepo
$ envi capture
 Finding repository root...
 Repository root: /Users/you/my-monorepo
 Package name: @myorg/monorepo
 Searching for .env files...
 Found 7 file(s):
  - .env
  - apps/web/.env.local
  - apps/web/.env.production
  - apps/api/.env.development
  - packages/core/.env.test
  - services/auth/.env
  - services/notifications/.env.production

Stored as: ~/.envi/store/@myorg/monorepo.maml

Running from Subdirectory

Envi automatically finds the repository root:

bash
$ cd apps/web
$ envi capture
 Finding repository root...
 Repository root: /Users/you/my-monorepo  # Found root!
...

It traverses up looking for version control markers (.git, .jj, .hg, .svn), so you can run it from anywhere in the monorepo.

Stored Format

maml
{
  __envi_version: 1
  metadata: {
    updated_from: "/Users/you/my-monorepo"
    updated_at: "2025-11-01T12:00:00.000Z"
  }
  files: [
    {
      path: ".env"
      env: { ROOT_VAR: "value" }
    }
    {
      path: "apps/web/.env.local"
      env: { WEB_API: "http://localhost:3000" }
    }
    {
      path: "services/auth/.env"
      env: { AUTH_SECRET: "secret" }
    }
  ]
}

Restoring

Restore recreates all files at their original locations:

bash
$ envi restore
...
 Restored 7 file(s):
 .env
 apps/web/.env.local
 apps/web/.env.production
 apps/api/.env.development
 packages/core/.env.test
 services/auth/.env
 services/notifications/.env.production

Best Practices

1. Use Scoped Package Name

In your root package.json:

json
{
  "name": "@myorg/monorepo",
  "private": true
}

This ensures:

  • Unique storage path: ~/.envi/store/@myorg/monorepo.maml
  • No conflicts with other projects
  • Organized by organization

2. Respect .gitignore

Envi reads your .gitignore to skip directories:

gitignore
node_modules
dist
.turbo
.next

But it still finds .env files even if they're in .gitignore (which is what you want).

3. Run from Root

While Envi can find the root from subdirectories, it's clearer to run from the root:

bash
# Clear and explicit
cd /path/to/monorepo
envi capture

# Also works, but less obvious
cd /path/to/monorepo/packages/web
envi capture  # Still captures entire monorepo

Turborepo Example

my-turborepo/
├── package.json              # "@myorg/turborepo"
├── turbo.json
├── .env
├── apps/
│   ├── docs/
│   │   └── .env.local
│   └── web/
│       ├── .env.local
│       └── .env.production
└── packages/
    ├── ui/
    │   └── .env.test
    └── config/
        └── .env

Capture all 6 env files:

bash
$ envi capture
 Found 6 file(s):
  - .env
  - apps/docs/.env.local
  - apps/web/.env.local
  - apps/web/.env.production
  - packages/ui/.env.test
  - packages/config/.env

pnpm Workspace Example

pnpm-workspace/
├── package.json              # "@company/workspace"
├── pnpm-workspace.yaml
├── .env
└── packages/
    ├── frontend/
    │   └── .env.local
    ├── backend/
    │   ├── .env.development
    │   └── .env.production
    └── shared/
        └── .env

All env files captured and organized by path.

Git Worktree with Monorepos

Perfect for working on multiple features simultaneously:

bash
# Main workspace
cd my-monorepo
envi capture

# Create worktree for feature
git worktree add ../monorepo-feature feature-branch
cd ../monorepo-feature
envi restore  # All env files restored!

# Another worktree
git worktree add ../monorepo-bugfix bugfix-branch
cd ../monorepo-bugfix
envi restore  # Same configs, different worktree

Limitations

Single Configuration per Monorepo

Each monorepo has one stored configuration file. You cannot:

  • Capture only specific packages
  • Have different configurations for different branches

All env files are captured together and restored together.

Package.json Name Required

For proper identification, add a name to your root package.json:

json
{
  "name": "@myorg/monorepo", // Required for uniqueness
  "private": true
}

Without it, Envi uses the folder name, which may conflict if you have multiple monorepos with the same folder name.

Released under the MIT License.