Env Sync
Env Sync automatically synchronizes matched environment files for each Git project with a dedicated repository.
Use it when you want a single private repo to back up, share, and restore .env-style files per project without manually copying them around.
Features
- Configure one existing private Git repository as the env config repository
- Recursively discover Git projects inside the current workspace folder
- Detect each discovered Git project's
origin and map it to a fixed folder in the config repository
- Pull matched env files when a workspace opens
- Commit and push matched env file changes after local edits
- Prompt instead of silently overwriting when local and remote contents differ
- Match files with multiple Git-project-relative path regexes
- Show current sync state in the VS Code status bar
- Skip configured directory names while recursively searching for Git projects
- Classify common Git failures like auth, network, push rejection, and rebase conflicts
How It Works
Env Sync scans the current workspace folder for Git projects up to a configurable depth and reads each discovered project's remote.origin.url.
Each Git project is normalized to:
github.com/<owner>/<repo>
Examples:
git@github.com:team/app.git
https://github.com/team/app.git
ssh://git@github.com/team/app.git
All map to:
github.com/team/app
Inside the config repository, files are stored at:
projects/<host>/<owner>/<repo>/
For example:
projects/github.com/team/app/.env.local
projects/github.com/team/app/config/.env.dev
Sync Behavior
On workspace open:
- Search for Git projects under the current workspace folder
- Remote exists, local missing: pull remote file into that Git project's root
- Local exists, remote missing: prompt
Upload local or Skip
- Both exist and are identical: do nothing
- Both exist and differ: prompt
Pull remote, Upload local, or Skip
On local file change:
- Matched file create or change events are debounced for 3 seconds
- Changes are mirrored into the config repository
- The config repository is committed and pushed automatically
- Deletes are mirrored to the config repository too
All sync jobs run through a single serial queue so multiple workspaces or nested projects do not race on the same config repository clone.
Status Bar And Errors
Env Sync adds a status bar item:
$(check): idle
$(sync~spin): a workspace-open or push sync is running
$(error): the last sync failed
Click the status bar item to open the Env Sync output channel.
Common Git failures are classified into clearer messages, including:
- repository access denied
- network access failed
- push rejected by the remote
- rebase or merge conflict
- Git executable unavailable
Requirements
- VS Code 1.112.0 or newer
git installed on the machine running the extension host
- A private Git repository already created for env sync data
- Working Git authentication, such as SSH keys or a credential helper
git config user.name and git config user.email configured for commits
Settings
envSync.configRepoUrl
The private Git repository used to store synchronized env files.
Example:
git@github.com:your-org/env-config.git
envSync.configRepoBranch
The branch used in the config repository.
Default:
main
envSync.pathRegexes
An array of JavaScript regex strings matched against Git-project-relative POSIX paths. A file is synchronized when any regex matches.
Default:
[
"^\\.env[^/]*$"
]
That default matches only root-level files starting with .env, such as:
.env
.env.local
.env.production.local
It does not match nested files like config/.env.local.
envSync.gitProjectSearchDepth
Controls how many directory levels below the workspace root are searched for Git projects.
Default:
2
Examples:
0: only check the workspace root itself
1: check the workspace root and its direct child directories
2: check the workspace root, children, and grandchildren
If you open a parent folder that contains multiple sibling repositories, this setting controls how deep Env Sync looks for them.
envSync.gitProjectIgnoreDirectories
Directory names skipped while recursively searching for Git projects under the workspace root.
Default:
[
"node_modules",
"dist",
"build",
".next",
".turbo",
".pnpm-store"
]
This setting only affects Git project discovery. It is useful when you open a large parent folder and want Env Sync to ignore generated output or package-store directories.
envSync.notificationLevel
Controls how much Env Sync reports through VS Code notifications.
Default:
"summary"
Available values:
errors: only show error notifications
summary: show successful sync summaries when files were actually pulled, uploaded, updated, or deleted
all: also show no-op checks, such as when a project was scanned and nothing needed to change
Examples:
Sync only root .env* files:
{
"envSync.pathRegexes": [
"^\\.env[^/]*$"
]
}
Sync root .env* files and config/.env* files:
{
"envSync.pathRegexes": [
"^\\.env[^/]*$",
"^config/\\.env[^/]*$"
],
"envSync.gitProjectIgnoreDirectories": [
"node_modules",
"dist",
"coverage"
]
}
Sync only .env and .env.local:
{
"envSync.pathRegexes": [
"^\\.env$",
"^\\.env\\.local$"
]
}
Sync root .env* files and one specific secret file:
{
"envSync.pathRegexes": [
"^\\.env[^/]*$",
"^secrets/\\.runtime\\.env$"
]
}
envSync.pathRegex
Deprecated single-regex fallback. New setups should use envSync.pathRegexes.
Command
Env Sync: Initialize Config Repo
Prompts for:
- Config Repo URL
- Config Repo Branch
The extension validates the repository with git ls-remote before saving the configuration.
Development
Install dependencies:
npm install
Build:
npm run build
Run tests:
npm test
Launch the extension in VS Code:
- Open this repository in VS Code
- Press
F5
- Select
Run Env Sync Extension
The project already includes .vscode/launch.json for extension debugging.
Packaging
Build a VSIX locally:
npm run package:vsix
This uses the locally installed @vscode/vsce binary to create a .vsix package from the built extension.
Publishing To The Marketplace
Before publishing:
- Create or confirm your Marketplace publisher ID
- Make sure the
publisher field in package.json matches that exact publisher ID
- Create an Azure DevOps Personal Access Token with Marketplace
Manage scope
- Log in with
vsce
- Publish
Typical commands:
npx @vscode/vsce login <publisher-id>
npm run deploy
If you prefer manual upload:
npm run package:vsix
Then upload the generated .vsix in the Marketplace publisher management page.
GitHub Actions Release Flow
This repository includes a release workflow at .github/workflows/publish.yml.
Behavior:
- Pull requests to
main: run install and test only
- Pushes to
main: run install and test only
- Pushes of tags matching
v*: run validation, package the extension, upload the VSIX artifact, and publish to the Visual Studio Marketplace
- Manual dispatch: optionally publish the current
main branch
Required GitHub secret
Create this repository secret:
VSCE_PAT: your Azure DevOps Marketplace Personal Access Token with Marketplace > Manage scope
Recommended release process
- Update
package.json version and CHANGELOG.md
- Commit to
main
- Create a matching Git tag, for example
v0.1.0
- Push the branch and tag
Example:
git tag v0.1.0
git push origin main
git push origin v0.1.0
The workflow validates that the Git tag version matches package.json before publishing.
Manual publish
You can also run the workflow manually from GitHub Actions by enabling the publish input. Manual publish is restricted to the main branch in the workflow.
Manual Test Flow
Create a local bare repo to simulate the config repository:
mkdir -p /tmp/env-sync-demo
cd /tmp/env-sync-demo
git init --bare config.git
git clone /tmp/env-sync-demo/config.git config-seed
cd config-seed
git config user.name tester
git config user.email tester@example.com
echo "# seed" > README.md
git add README.md
git commit -m init
git branch -M main
git push -u origin main
Create a test project:
cd /tmp/env-sync-demo
mkdir app
cd app
git init
git config user.name tester
git config user.email tester@example.com
git remote add origin git@github.com:team/app.git
echo "A=1" > .env.local
mkdir -p config
echo "B=2" > config/.env.dev
Example settings:
{
"envSync.configRepoUrl": "/tmp/env-sync-demo/config.git",
"envSync.configRepoBranch": "main",
"envSync.pathRegexes": [
"^\\.env[^/]*$",
"^config/\\.env[^/]*$"
]
}
Open the test project in the extension host, initialize the config repo, and validate:
- First upload prompt
- Automatic push after save
- Delete propagation
- Pull on reopen or reload
Limitations
- Only file-system workspaces are supported
- Untrusted workspaces are not supported
- Virtual workspaces are not supported
- The extension does not create the GitHub repository for you
- The extension does not encrypt secrets before commit
- Project mapping is fixed to
origin -> projects/<host>/<owner>/<repo>/
Release Notes
See CHANGELOG.md.