Securely sync your .env files across machines with military-grade encryption.
A blazingly fast CLI tool built for developers who manage multiple projects across different machines. Scan once, sync everywhere. Keep your environment variables in perfect sync between your work laptop, home desktop, and MacBook without manual copying.
⚠️ IMPORTANT: This tool handles sensitive secrets. Review the source code before use and build from source for production use. See Build from Source below.
- Recursive Scanning - Finds all
.envfiles in your projects automatically - Military-Grade Encryption - AES-GCM with Argon2 key derivation
- Smart Bidirectional Sync - SHA-256 hash comparison + timestamp-based conflict resolution
- Git-Based Identification - Files are identified by git remote URL, so the same repo syncs correctly across machines regardless of where it's cloned
- Parallel Processing - Configurable worker pool for fast syncing (default: 10 workers)
- Multiple Databases - Turso/LibSQL and PostgreSQL support
- Dry Run Mode - Preview changes before applying
- Cross-Platform - Works on Windows, macOS (Apple Silicon), and Linux
- Fast & Lightweight - Written in Go, single binary, no dependencies
- Secure by Design - Files never leave your machine unencrypted
- Performance Metrics - See detailed timing and throughput stats after each sync
Developers with multiple projects across multiple machines.
If you have a base directory like ~/Projects or D:\Github with dozens of repos, each with their own .env files, and you switch between:
- Work laptop
- Home desktop
- Personal MacBook
- Remote dev server
...then this tool is for you. Scan your entire projects folder once, and keep all environment files in sync across every machine.
Recommended Setup: Add env-sync sync to a cron job or scheduled task on each machine to automatically sync every hour or on login.
For production use, always build from source after reviewing the code:
# Clone and review the repository
git clone https://github.com/markibanez/env-sync.git
cd env-sync
# Review the source code (IMPORTANT - this handles your secrets!)
# Check: main.go, crypto.go, database.go, sync.go
# Install dependencies
go mod download
# Build for your platform
go build -o env-sync
# Move to your PATH
sudo mv env-sync /usr/local/bin/ # macOS/Linux
# or add to PATH on WindowsIf you trust the releases, download from Releases:
macOS (Apple Silicon):
curl -L https://github.com/markibanez/env-sync/releases/latest/download/env-sync-macos-arm64 -o env-sync
chmod +x env-sync
sudo mv env-sync /usr/local/bin/Windows (PowerShell):
# Download from releases and add to PATHLinux:
curl -L https://github.com/markibanez/env-sync/releases/latest/download/env-sync-linux -o env-sync
chmod +x env-sync
sudo mv env-sync /usr/local/bin/# 1. Scan for .env files in your projects
env-sync scan ~/Projects
# 2. Sync to cloud database (upload newer, download newer)
env-sync sync \
--db "libsql://your-db.turso.io?authToken=eyJhbGc..." \
--password "your-secret-password"
# 3. Preview changes without applying (dry run)
env-sync sync \
--db "libsql://your-db.turso.io?authToken=eyJhbGc..." \
--password "your-secret-password" \
--dry-runRecursively scans a directory for .env files and remembers their locations.
env-sync scan /path/to/projectsFeatures:
- Finds all
.env,.env.local,.env.production, etc. - Skips
node_modules,vendor, and hidden directories - Stores file paths locally for sync operations
Smart bidirectional sync with hash comparison and timestamp-based conflict resolution.
env-sync sync \
--db "libsql://db-name.turso.io?authToken=..." \
--password "encryption-password" \
--base "/path/to/projects" \
--workers 20 \
--dry-runFlags:
--db- Database connection string (required)--password- Encryption password (required)--base- Base path for relative paths (default: current directory)--workers- Number of parallel workers (default: 10)--dry-run- Preview changes without applying
Sync Logic:
- Git-based identification - Files are matched by git remote URL + relative path within repo
github.com/user/repo+.env= unique identifier- Works regardless of where repo is cloned on each machine
- Non-git directories fall back to relative path from base
- Hash comparison first (most reliable)
- If hashes match → Skip (files are identical)
- Timestamp comparison (if hashes differ)
- Local newer → Upload to database
- Remote newer → Download from database
- Same time, different content → Upload local (prefer local changes)
Example Output:
Syncing 59 .env file(s) with 10 workers...
↑ Uploaded: .env (markibanez/myproject) (new)
↓ Downloaded: .env (user/webapp) (remote newer)
= Skipped: .env (org/api) (identical)
--------------------------------------------------
Sync Summary:
↑ Uploaded (local newer): 12
↓ Downloaded (remote newer): 3
= Skipped (same): 44
--------------------------------------------------
Performance:
Total files: 59
Workers used: 10
DB connect time: 245ms
Sync time: 1.823s
Total time: 2.071s
Throughput: 32.4 files/sec
Force upload all scanned files to the database (overwrites remote).
env-sync upload \
--db "postgres://user:pass@localhost:5432/dbname" \
--password "encryption-password"Download all files from database to a specified directory.
env-sync download \
--db "libsql://db-name.turso.io?authToken=..." \
--password "encryption-password" \
--output "./restored-env-files"List all remembered .env files from the last scan.
env-sync listRun as a background daemon that syncs automatically at a specified interval.
env-sync daemon \
--db "libsql://db-name.turso.io?authToken=..." \
--password "encryption-password" \
--base "/path/to/projects" \
--interval 1h \
--workers 10Flags:
--db- Database connection string (required)--password- Encryption password (required)--base- Base path for relative paths (default: current directory)--interval- Sync interval (default: 1h). Supports Go duration format:30m,1h,2h30m--workers- Number of parallel workers (default: 10)
Features:
- Runs initial sync immediately on startup
- Continues syncing at the specified interval
- Graceful shutdown with Ctrl+C or SIGTERM
- No popup windows (unlike scheduled tasks)
- Logs each sync with timestamps
Example Output:
env-sync daemon starting...
Database: libsql://your-db.turso.io...
Base path: D:\Github
Interval: 1h0m0s
Workers: 10
[2024-01-15 10:00:00] Running initial sync...
Syncing 59 .env file(s) with 10 workers...
Uploaded: 3, Downloaded: 1, Skipped: 55
[2024-01-15 10:00:02] Sync complete. Next sync in 1h0m0s. Press Ctrl+C to stop.
[2024-01-15 11:00:02] Running scheduled sync...
Syncing 59 .env file(s) with 10 workers...
Uploaded: 0, Downloaded: 2, Skipped: 57
[2024-01-15 11:00:04] Sync complete. Next sync in 1h0m0s. Press Ctrl+C to stop.
Running as a Windows Service:
For true invisible background operation on Windows, use NSSM (Non-Sucking Service Manager):
# Download NSSM from https://nssm.cc/download
# Install as a service
nssm install env-sync "C:\path\to\env-sync.exe" "daemon --db \"libsql://...\" --password \"...\" --base \"D:\Github\" --interval 1h"
# Start the service
nssm start env-sync
# Check status
nssm status env-sync
# Remove service
nssm remove env-syncRunning on macOS/Linux with systemd:
# Create service file
sudo nano /etc/systemd/system/env-sync.service[Unit]
Description=env-sync daemon
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/env-sync daemon --db "libsql://..." --password "..." --base "/home/user/Projects" --interval 1h
Restart=always
User=youruser
[Install]
WantedBy=multi-user.target# Enable and start
sudo systemctl enable env-sync
sudo systemctl start env-sync
sudo systemctl status env-syncTurso is a distributed SQLite database perfect for this use case.
# Install Turso CLI
brew install tursodatabase/tap/turso # macOS
# or
curl -sSfL https://get.tur.so/install.sh | bash # Linux/WSL
# Create database
turso db create env-sync
# Get database URL
turso db show env-sync --url
# Output: libsql://env-sync-yourname.turso.io
# Create auth token
turso db tokens create env-sync
# Output: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...
# Use in env-sync
env-sync sync \
--db "libsql://env-sync-yourname.turso.io?authToken=eyJhbGc..." \
--password "my-secret-password"env-sync sync \
--db "postgres://user:password@localhost:5432/env_sync" \
--password "my-secret-password"- Encryption: AES-256-GCM (Galois/Counter Mode)
- Key Derivation: Argon2id with 64MB memory, 4 threads, 1 iteration
- Random Salt: 16 bytes per file
- Random Nonce: 12 bytes per encryption
- Hash Verification: SHA-256 for content comparison
- Zero Knowledge: Database stores only encrypted content, never plaintext
Database Schema:
CREATE TABLE env_files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
repo_id TEXT NOT NULL, -- Git remote URL (e.g., github.com/user/repo) or "__local__"
relative_path TEXT NOT NULL, -- Path relative to repo root (e.g., .env or packages/api/.env)
contents TEXT NOT NULL, -- AES-GCM encrypted + base64
file_hash TEXT NOT NULL, -- SHA-256 of plaintext
file_modified_at DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(repo_id, relative_path)
);# Clone the repository
git clone https://github.com/markibanez/env-sync.git
cd env-sync
# Install dependencies
go mod download
# Build for your platform
go build -o env-sync
# Or cross-compile for all platforms
GOOS=darwin GOARCH=arm64 go build -o env-sync-macos-arm64
GOOS=windows GOARCH=amd64 go build -o env-sync-windows.exe
GOOS=linux GOARCH=amd64 go build -o env-sync-linuxFor seamless multi-machine development, set up automated syncing:
Run the built-in daemon for true background operation with no popup windows:
# Run in background
env-sync daemon \
--db "libsql://db-name.turso.io?authToken=..." \
--password "encryption-password" \
--base "D:\Github" \
--interval 1h
# For Windows, install as a service with NSSM (see daemon command docs)
# For Linux/macOS, use systemd (see daemon command docs)Use cron (macOS/Linux) or Task Scheduler (Windows) to run env-sync sync periodically.
Run it every hour, every 30 minutes, or on system login.
Primary Use Case: Multi-Machine Development with Many Projects
You have ~/Projects or D:\Github with 50+ repos, each with their own .env files. You work on:
- MacBook Pro at the coffee shop
- Windows desktop at home
- Linux workstation at the office
Instead of manually copying files or using git (which you shouldn't for secrets), run env-sync scan ~/Projects once, then env-sync sync on each machine. All your environment files stay in sync automatically.
Other Use Cases:
- Team Onboarding - Share encrypted environment configs with new team members
- Backup & Recovery - Never lose API keys or database credentials again
- CI/CD Secrets - Securely pull environment variables in deployment pipelines
- Freelance/Consulting - Keep client project configs organized and synced
Q: What happens if I forget my password? A: Your files are encrypted with your password. Without it, decryption is impossible. Store your password in a password manager.
Q: Can I use different passwords for different projects? A: Yes! Use different databases or different passwords. The tool doesn't restrict this.
Q: Does this replace .env.example files?
A: No. Keep .env.example in your repos with dummy values. Use env-sync for actual secrets.
Q: What files are synced?
A: Files matching .env* pattern (.env, .env.local, .env.production, etc.)
Q: Is this safe for production secrets? A: The encryption is production-grade, but review your threat model. For high-security needs, consider HashiCorp Vault or AWS Secrets Manager.
MIT License - see LICENSE file for details.
Contributions welcome! Open an issue or submit a PR.
- GitHub: markibanez/env-sync
- Issues: Report a bug
- Turso Database: turso.tech
Made with ❤️ by @markibanez
Keep your secrets safe, sync them everywhere.