EditSyncSafe, backup-first remote server sync for VS Code and CLI. EditSync backs up the server file before every upload, detects when someone else changed it, and moves deleted files to a recoverable trash instead of erasing them. Why EditSync?Other remote sync tools silently overwrite server files, delete without undo, and ignore conflicts. One wrong save can destroy hours of work on a production server. EditSync was built on a single principle: the server file must never be lost.
Feature Comparison: Free vs Pro vs Team
Get Pro / Team14-day free trial with every Pro feature. No credit card required. What happens on the Free plan
Quick Start1. InstallSearch "EditSync" in VS Code Extensions, or:
2. Create Config
If you have 3. Edit ConfigPassword:
Private key:
If the config is invalid, EditSync tells you which field is wrong and offers Open Config. 4. ConnectClick the status bar at the bottom, or run If 5. Download Server FilesFirst connection prompts:
On reconnect, if you have sync history, this dialog is skipped automatically. If you leave it unanswered, uploads stay paused and EditSync reminds you with the same choices when you save. 6. Start WorkingSave files normally. EditSync automatically:
Images, fonts, and binary files are auto-uploaded when copied into the project. ConfigurationFull
|
| Setting | Default | Description |
|---|---|---|
editsync.autoConnect |
true |
Connect automatically when the workspace has .vscode/editsync.json |
editsync.showStatusBar |
true |
Show the connection status in the status bar |
editsync.uploadDebounceMs |
300 |
Upload delay after a save (used when watcher.delay is not set) |
editsync.confirmDelete |
true |
Ask before moving a deleted/renamed file to the server trash |
Built-in Ignore (always excluded, no config needed)
.git, node_modules, .DS_Store, Thumbs.db (at any depth), .vscode/** and .trash/** (at the root),
the configured backup.path, and EditSync's own server files (.locks/,
.editsync-team.json). Ignored directories are not scanned at all during initialize.
Ignore Patterns
ignore works like .gitignore:
- A pattern without a slash matches a file or folder name at any depth:
*.logalso excludeslogs/app.log,buildexcludes everybuildfolder. - A pattern with a slash is relative to the project root:
dist/**excludes only the top-leveldist.
Initialize Method
| Method | Use case |
|---|---|
sftp (default) |
Standard file-by-file download |
tar (Pro) |
Fast bulk download via tar archive (large projects, requires tar on the server and locally). Only the files a normal initialize would download are written -- ignored paths, .git and .vscode are never overwritten. |
Hooks (Pro)
| Hook | Runs on | Example |
|---|---|---|
beforeUpload |
Local (before upload) | "npm run lint" |
afterUpload |
Server via SSH (after upload) | "pm2 restart app" |
beforeDownload |
Local (before download) | "git stash" |
afterDownload |
Local (after download) | "npm run build" |
Env vars: EDITSYNC_FILE (local path), EDITSYNC_REMOTE (remote path).
A failing beforeUpload / beforeDownload (exit code != 0) cancels the transfer. A failing afterUpload / afterDownload is reported but does not undo it.
Auth Methods
| Method | Use case |
|---|---|
password |
Simple password |
privateKey |
SSH key (.pem, .ppk, with optional passphrase) |
agent |
SSH agent forwarding (SSH_AUTH_SOCK must be set) |
interactive |
2FA / OTP. VS Code asks for the code in an input box, the CLI asks in the terminal. If auth.password is set, it is used to answer instead. |
Connection Types
SFTP (Standard)
{ "type": "sftp", "host": "192.168.0.100", "port": 22, "username": "root",
"auth": { "method": "password", "password": "your-password" } }
SFTP + Jump Host (Pro)
{ "type": "sftp", "host": "10.0.0.5", "port": 22, "username": "deploy",
"auth": { "method": "privateKey", "privateKeyPath": "~/.ssh/id_rsa" },
"jumpHost": { "host": "bastion.company.com", "port": 22, "username": "jump-user" } }
SFTP + Multi-hop (A → B → target) (Pro)
Nest jumpHost to chain several hops. The outermost entry is the hop closest to
the target, so the example below connects edge → bastion → 10.0.0.5.
{ "type": "sftp", "host": "10.0.0.5", "port": 22, "username": "deploy",
"auth": { "method": "privateKey", "privateKeyPath": "~/.ssh/id_rsa" },
"jumpHost": {
"host": "bastion.internal", "port": 22, "username": "jump-user",
"jumpHost": { "host": "edge.company.com", "port": 22, "username": "edge-user" }
} }
Using your ~/.ssh/config (Pro)
Set sshConfigPath and use the SSH alias as host. EditSync resolves HostName,
Port, User, IdentityFile and ProxyJump (including multi-hop) from that file.
Anything you write directly in editsync.json wins over the SSH config.
{ "type": "sftp", "host": "my-server", "sshConfigPath": "~/.ssh/config" }
Kubernetes Pod (Pro)
{ "type": "k8s", "host": "my-pod-name", "username": "default" }
host= pod name,username= namespace. Requireskubectl. The pod needsfind -printfandstat -c-- BusyBox-based images list no files.
AWS SSM Session Manager (Pro)
{ "type": "aws-ssm", "host": "i-0123456789abcdef0", "username": "ec2-user" }
No SSH keys needed. Requires AWS CLI + SSM plugin. Files larger than about 17 KB need
EDITSYNC_S3_BUCKETset to transfer through S3.
Commands
| Command | Tier | Description |
|---|---|---|
EditSync: Connect to Server |
Free | Connect to server |
EditSync: Disconnect |
Free | Disconnect |
EditSync: Upload Current File |
Free | Upload active file |
EditSync: Download Current File |
Free | Download from server (active file, or the file right-clicked in Remote Explorer) |
EditSync: Download Folder |
Free | Right-click a folder in Remote Explorer |
EditSync: Open Remote File |
Free | Click or right-click a file in Remote Explorer |
EditSync: Initialize (Download from Server) |
Free | Download all server files |
EditSync: Create Config File |
Free | Generate config (SSH config host picker) |
EditSync: Refresh Remote Explorer |
Free | Refresh remote file tree |
EditSync: Compare with Server Version (Pro) |
Pro | Diff local vs server |
EditSync: Show File History (Pro) |
Pro | Timeline UI with restore |
EditSync: Show File Backups (Pro) |
Pro | List backup versions |
EditSync: Export Changes (Pro) |
Pro | Export changed files list |
EditSync: Switch Server Profile (Pro) |
Pro | Switch between profiles |
EditSync: Save Current as Profile (Pro) |
Pro | Save config as profile |
EditSync: Activate Pro License |
-- | Enter license key |
How It Works
Save -> Upload
Save file -> [hooks] beforeUpload (Pro) -> mtime check -> conflict?
No -> backup server file (Pro) -> upload -> size check -> [hooks] afterUpload (Pro)
Yes -> Pro: choose Backup & Overwrite / Overwrite / Skip / Compare
(Backup All / Skip All stop asking for 10 minutes)
Free: overwrite
Saving within the first seconds after opening a file is not lost: the upload waits until sync-on-open finishes.
Open File -> Sync
Open file -> check server mtime (30s cooldown)
Same -> no action
Changed -> backup local (Pro) -> download server version -> reload editor
(unsaved edits -> asks before discarding them)
Delete / Rename
Delete or rename locally -> Pro: confirm -> move old path to server .trash/ (7-day recovery)
-> Free: server file untouched (with a notice)
Initialize
Connect -> first time? "Download All / Browse / Skip"
Download All -> scan server (ignored dirs skipped) -> skip unchanged files
-> backup changed local files (Pro) -> parallel download (10x)
Reconnect (has history) -> skip dialog, ready to work
Status Bar
| State | Click action |
|---|---|
| Disconnected | Connect |
| Connected | Disconnect |
Syncing ↓ 35% (7/20) src/index.js |
Disconnect |
| Conflict | Disconnect |
| Error | Connect |
CLI
npm install -g editsync
editsync init # Create config
editsync connect # Test connection
editsync pull # Download all (server -> local)
editsync pull src/app.js # Download specific file
editsync push src/app.js # Upload specific file
editsync watch # Watch + auto-upload (Pro)
editsync status # Sync status
editsync diff src/app.js # Compare local vs server (Pro)
editsync backups src/app.js # List backups (Pro)
editsync export today # Export changes (Pro)
editsync activate SEP-XXXX # Activate license
The CLI follows the same plan rules as the extension: Free is limited to 1 server, Pro-only connection methods are refused, and Team uploads respect file locks. Commands that only read local data (status, backups, export) do not count toward the server limit.
Activating Pro
- Click Get Pro (or Get Team) on any upgrade prompt
- The checkout opens in your browser, and a license key input box opens in VS Code
- Complete the purchase and paste the key -- Pro activates immediately and the connection is refreshed with Pro settings
Or: Ctrl+Shift+P -> EditSync: Activate Pro License. CLI: editsync activate <key>.
| Key prefix | Plan |
|---|---|
SEP- |
Pro |
SET- |
Team |
Your license key also arrives by email -- if you close the key box before it arrives, enter it any time with EditSync: Activate Pro License.
The license is checked when EditSync starts and every 24 hours after that (at most once a day online). Without network access, or while the license service is down, it stays valid for 7 days. A refunded or revoked license switches back to Free and disconnects. Each computer uses its own activation, so the device limit of your plan applies (a license file copied from another computer is re-activated on this one).
Pricing
| Plan | Monthly | Yearly | Features |
|---|---|---|---|
| Free | $0 | $0 | Basic sync, 1 server, no safety net |
| Pro | $2.90 / mo | $19 / yr | Backup, conflict, trash, unlimited servers, hooks, profiles, advanced connections |
| Team | $4.90 / mo | $4.90 / yr | Pro + file locking + shared team config |
14-day free trial. 14-day money-back guarantee.
Team Features
File Locking
When a Team user uploads a file, it is locked on the server (.locks/). Other team members see "Locked by {user}" and cannot overwrite it. Locks are refreshed while you work, released on disconnect, and treated as stale after 1 hour. This applies to both the extension and the CLI.
Shared Config
Place .editsync-team.json on your server (in remotePath). On connect, its ignore patterns and its afterUpload hook (which runs on the server) are merged into every Team member's settings. Hooks that would run on a member's own computer (beforeUpload, beforeDownload, afterDownload) are ignored here for safety -- set those in your own editsync.json.
{
"ignore": ["*.log", "tmp/**"],
"hooks": { "afterUpload": "systemctl reload nginx" }
}
FAQ
Is my data sent to EditSync servers? No. Files travel directly between your machine and your server via SSH/SFTP. Only license validation calls go to Polar.sh. See PRIVACY.md.
What happens when the trial expires? Pro features lock. Basic sync continues on 1 server. Existing backups remain on disk. Configs that use a Pro-only connection method (Jump Host, SSH config, K8s, AWS SSM) stop connecting until you upgrade.
Where are backups stored? Locally in .vscode/editsync-backup/. Not cloud-backed. Auto-cleaned: init backups keep last 3, per-file backups keep last 10, trash cleaned after 7 days.
Why Pro for production? Free uploads without backup. One accidental overwrite = permanent loss. Pro backs up every upload and warns on conflicts.
Can I run commands after upload? Yes, on Pro. Use hooks.afterUpload -- runs on the server via SSH.
Kubernetes? Yes, on Pro. Set connection.type to "k8s". No SSH needed.
Connection drops? A 60-second heartbeat detects drops and reconnects. Failed uploads are queued and retried on reconnect. An upload cut short by a drop is detected by its size and is not marked as synced.
Large project slow to initialize? On Pro, set "initialize": { "method": "tar" } for bulk download via tar archive. Requires tar on server.
Important
- Backups are local only. Always maintain independent backups.
- Free tier has no safety net. Use Pro for production.
- Server is Source of Truth. Initialize downloads from server.
- See LICENSE.txt for full terms.
- See PRIVACY.md for privacy policy.
License
Proprietary. See LICENSE.txt.
Copyright (c) 2025-2026 DkLib. All rights reserved.
Contact: eorud0713@gmail.com