Quickly switch between .env files. Copies
.env.<environment> to .env.local (or a custom target) and
tracks the active environment via a header comment. Works with
Next.js, Vite, Remix, and any project that uses .env files.
npm install -g dotswitchOr use directly without installing:
npx dotswitch use staging# Switch to .env.staging → .env.local
dotswitch use staging
# Interactive picker (when no env specified)
dotswitch use
# Skip backup of existing .env.local
dotswitch use production --no-backup
# Force switch even if already active
dotswitch use staging --force
# Preview what would happen without making changes
dotswitch use staging --dry-rundotswitch lsAvailable environments:
▸ staging (active)
production
preview
JSON output for scripts:
dotswitch ls --json
# [{"name":".env.staging","env":"staging","active":true},{"name":".env.production","env":"production","active":false}]dotswitch currentJSON output:
dotswitch current --json
# {"active":"staging"}Pipe-friendly — outputs the plain env name when not a TTY:
ENV=$(dotswitch current)# Restore .env.local from .env.local.backup
dotswitch restore# Compare current .env.local against .env.production
dotswitch diff production
# Compare two environments directly
dotswitch diff staging production
# Show actual values (not just key names)
dotswitch diff staging production --show-values
# JSON output
dotswitch diff staging production --jsonAll commands support:
| Flag | Description |
|---|---|
-p, --path <dir> |
Project directory (defaults to cwd) |
--json |
Output as JSON (machine-readable) |
use also supports:
| Flag | Description |
|---|---|
-f, --force |
Switch even if already active |
--no-backup |
Skip .env.local backup |
-n, --dry-run |
Preview what would happen |
Create a .dotswitchrc.json in your project root to customize
behavior. Everything is optional — dotswitch works out of the
box without a config file.
{
"target": ".env.local",
"exclude": [".env.test"],
"hooks": {
"main": "production",
"staging/*": "staging",
"dev*": "development"
}
}| Field | Default | Description |
|---|---|---|
target |
".env.local" |
File to write the active env to |
exclude |
[] |
Additional env files to hide from ls |
hooks |
{} |
Branch-to-env mappings for git hook auto-switching |
By default dotswitch writes to .env.local, but some
frameworks use .env directly. Set the target field to
change this:
{
"target": ".env"
}Automatically switch environments when you check out a branch.
- Add branch mappings to
.dotswitchrc.json:
{
"hooks": {
"main": "production",
"staging/*": "staging",
"develop": "development"
}
}- Install the git hook:
dotswitch hook installNow git checkout staging/feat-login will automatically run
dotswitch use staging.
"main"— exact branch name match"staging/*"— matchesstaging/prefix (e.g.,staging/feat-x)"dev*"— matches any branch starting withdev
dotswitch hook removeSwitch environments across multiple packages at once using glob patterns:
# Switch all apps to staging
dotswitch use staging --path "./apps/*"
# Check status across packages
dotswitch ls --path "./packages/*"Each directory is processed independently with labeled output.
dotswitch works transparently in
git worktrees. When
you run any command from a worktree, it automatically resolves
back to the main repo where your .env.* files and
.dotswitchrc.json live.
# From a worktree, all commands operate on the main repo
cd /path/to/my-worktree
dotswitch ls # lists envs from the main repo
dotswitch use staging # switches in the main repo
dotswitch hook install # installs hook in the shared .git/hooksExplicit --path arguments are rebased automatically, so
monorepo globs also work from worktrees:
dotswitch use staging --path "./apps/*"When you run dotswitch use staging, it:
- Backs up your existing
.env.localto.env.local.backup - Copies
.env.stagingto.env.local - Prepends a
# dotswitch:stagingheader to track the active environment
The header comment is how dotswitch ls and
dotswitch current know which environment is active.
dotswitch exports its core functions for use in scripts:
import {
listEnvFiles,
switchEnv,
getActiveEnv,
restoreEnvLocal,
loadConfig,
parseEnvContent,
diffEnvMaps,
resolveProjectRoot,
} from "dotswitch";
const files = listEnvFiles(process.cwd());
const active = getActiveEnv(process.cwd());
switchEnv(process.cwd(), "staging", { backup: true });In worktree-aware scripts, resolve the project root first:
const projectRoot = resolveProjectRoot(process.cwd());
const files = listEnvFiles(projectRoot);
switchEnv(projectRoot, "staging", { backup: true });- Node.js >= 20
MIT
