Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

env-sync

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.

Go License Cross-Platform


Features

  • Recursive Scanning - Finds all .env files 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

Who Is This For?

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.


Quick Start

Installation (Build from Source - Recommended)

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 Windows

Installation (Pre-built Binaries)

If 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 PATH

Linux:

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/

Basic Usage

# 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-run

Commands

scan <path>

Recursively scans a directory for .env files and remembers their locations.

env-sync scan /path/to/projects

Features:

  • Finds all .env, .env.local, .env.production, etc.
  • Skips node_modules, vendor, and hidden directories
  • Stores file paths locally for sync operations

sync

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-run

Flags:

  • --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:

  1. 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
  2. Hash comparison first (most reliable)
    • If hashes match → Skip (files are identical)
  3. 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

upload

Force upload all scanned files to the database (overwrites remote).

env-sync upload \
  --db "postgres://user:pass@localhost:5432/dbname" \
  --password "encryption-password"

download

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

List all remembered .env files from the last scan.

env-sync list

daemon

Run 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 10

Flags:

  • --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-sync

Running 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-sync

Database Setup

Turso/LibSQL (Recommended)

Turso 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"

PostgreSQL

env-sync sync \
  --db "postgres://user:password@localhost:5432/env_sync" \
  --password "my-secret-password"

Security

  • 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)
);

Build from Source

# 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-linux

Automated Sync (Recommended)

For seamless multi-machine development, set up automated syncing:

Option 1: Daemon Mode (Recommended)

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)

Option 2: System Scheduler

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.


Use Cases

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

FAQ

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.


License

MIT License - see LICENSE file for details.


Contributing

Contributions welcome! Open an issue or submit a PR.


Links


Made with ❤️ by @markibanez

Keep your secrets safe, sync them everywhere.

About

Synchronizes env file contents

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages