VNSync Documentation
Everything you need to keep Visual Novel and RPG saves in sync across Windows, macOS, Linux, and Steam Deck.
Quick start
- Download and install VNSync on every device you play on.
- Open Settings and pick a storage backend (S3, WebDAV, a shared folder, or your own VNSync Server). Click Test Connection, then Save Backend.
- Set a Device Name (for example
Desktop-Win11orSteam-Deck) so you can tell snapshots apart. - Click Add Game, pick the game executable, and click Detect to find the save folder.
- Open the game and click Sync Saves. Repeat on the other device and VNSync downloads the save.
Use the same storage backend settings on every device. Each device must point to the same bucket, WebDAV folder, shared folder, or server.
How VNSync works
- Snapshot: VNSync packs a game's save folder into a
.tar.zstarchive. A BLAKE3 hash of the content identifies it, so identical saves give the same hash. - Local vault: snapshots are kept on your device. You can restore any of them from the game page.
- Head: the newest snapshot for a game. Each snapshot remembers its parent, so VNSync knows which device's save came first.
- Remote: your storage backend holds
games/<game id>/head.json, the snapshot archives ingames/<game id>/snapshots/, and the library list inlibrary/catalog.json. - Portable path rules: save locations are stored with tokens like
<win_appdata>, so the same rule works on every OS.
Adding a game
Click Add Game on the library page.
- VNDB search (optional). Type the title in Search Visual Novel Title and click Search. Select a result to fill the title, original title, developer, release date, cover image, and synopsis.
- Game Executable. Click Browse and select the game's
.exeor binary. Click Detect. VNSync fingerprints the engine (Ren'Py, RPG Maker MV/MZ/VX Ace/VX/XP, Kirikiri/KAG, Unity) and fills the save path rule. - Wine / Proton Prefix (Linux / Steam Deck only). If the game runs through Proton, enter its prefix, for example
/home/deck/.local/share/Steam/steamapps/compatdata/12345. VNSync accepts the folder with or without the trailing/pfx. - Portable Save Path Rules. Check the detected rule. If detection fails:
- Select a preset from the save location database (for example Nitroplus or Key titles). Load Custom JSON lets you use your own preset file; Use Default switches back.
- Or type a rule and click Add Rule. Pick File / Pick Folder converts a real path into a portable rule for you.
- Check the metadata fields (title, developer, Play Status, cover URL, notes) and click Save to Library.
Save path tokens
Rules use tokens so one rule works on every OS. VNSync resolves them as follows:
| Token | Windows | macOS | Linux | Proton prefix set |
|---|---|---|---|---|
<game_dir> | Folder that contains the game executable | |||
<win_appdata> | %APPDATA% (Roaming) | ~/Library/Application Support | ~/.local/share | …/drive_c/users/steamuser/AppData/Roaming |
<win_locallow> | %USERPROFILE%\AppData\LocalLow | ~/Library/Application Support | ~/.config/unity3d | …/steamuser/AppData/LocalLow |
<win_documents> | Documents folder | Documents folder | Documents folder | …/steamuser/Documents |
<game_title> | The game's title, inside a path | |||
Ren'Py exception: <win_appdata>/RenPy/… maps to ~/Library/RenPy/… on macOS and ~/.renpy/… on Linux.
Examples: <game_dir>/savedata, <game_dir>/*.sav, <win_appdata>/RenPy/MyGame-1234567.
Game library
The home page lists every game with its engine, sync status, and play status. Use the filter box to search by title, developer, or engine.
- Play starts the game. With the auto-sync rules on, VNSync pulls newer saves first and snapshots and pushes after the game closes. Playtime is recorded.
- Locate Folder opens the game folder.
- Sync All syncs every game in one step.
- Right-click a game for quick actions.
Sync status values:
- Local Only: the game was never synced.
- Synced: local and remote heads match.
- Conflict: two devices changed the save separately. See conflicts.
Library Backup menu
- Backup Library to Cloud uploads your game list to
library/catalog.jsonin the active backend. - Restore Library from Cloud downloads that list and merges it into this device. Use it on a new device instead of adding every game again.
- Export / Import Library Backup (.json) does the same with a local file.
- Auto-Fix Wrong User Paths repairs executable paths that point to another user's home folder. See New PC & Steam Deck.
The library backup holds game entries and path rules only. Save files sync per game.
Game page & snapshots
Click a game to open its page.
- Sync Saves syncs this game with the remote.
- Snapshot saves the current save folder to the local vault. Type a checkpoint label first (for example
Choice A) to find it later. Use this before a big choice to keep each route. - The snapshot list shows each snapshot's device, time, and label.
HEADmarks the current one. Restore writes that snapshot back into the save folder. - Edit Paths changes the executable, save path rule, or Proton prefix. A Missing on this user/PC badge means the executable path is wrong on this device: click Select .exe or Select Folder.
- Edit Game opens the full editor: VNDB refresh, title, status, completion percentage, cover, notes, and save rules.
- Removing a game deletes its VNSync entry and local vault history. Your real save files on disk stay.
Syncing & conflicts
When you sync, VNSync compares the local head with the remote head:
| Situation | Result |
|---|---|
| No remote save yet | Uploads the local snapshot |
| No local save yet | Downloads the remote snapshot |
| Same snapshot on both sides | "Saves are already in sync" |
| Local save is newer and continues from the remote one | Fast-forward push |
| Remote save is newer and continues from the local one | Fast-forward pull |
| Both sides changed since their last common snapshot | Conflict |
Resolving a conflict
The game page shows Save Lineage Conflict Detected with the local and remote state side by side. Choose one:
- Keep Local & Push to Cloud replaces the remote save with this device's save.
- Pull Cloud & Restore Locally replaces this device's save with the remote save. A safety snapshot is taken first.
The losing side is not lost: the local one stays in the local vault, and the server keeps older snapshots in its history.
Storage backends
Configure the backend in Settings → Cloud & Storage Backend. Set Storage Backend Type, fill the fields, click Test Connection, then Save Backend.
| Type | Fields | Notes |
|---|---|---|
| S3-Compatible | Endpoint URL, Bucket Name, Region, Root Folder Prefix, Access Key ID, Secret Access Key | Cloudflare R2, AWS S3, MinIO, Backblaze B2. Leave Endpoint blank for AWS. Use region auto for R2. |
| WebDAV | WebDAV Endpoint URL, Username, Password / App Password | Nextcloud, ownCloud, Synology, Koofr. Nextcloud URL: https://cloud.example.com/remote.php/dav/files/username/. Use an app password. |
| Local / Shared Folder | Local / Network Sync Folder | Any folder another tool syncs: Syncthing, Google Drive, Dropbox, OneDrive, or an SMB share. |
| VNSync Server | Server URL, Token | Your own server. See Self-hosted server. |
head.json without that check. If two devices sync the same game at the same moment, one change can be overwritten. The VNSync Server rejects the second upload instead.Self-hosted server
The server/ folder in the repository is a small sync server for a home server, NAS, or VPS. Use it instead of S3 or WebDAV when you want to own the storage. It:
- stores saves as files in one data folder,
- rejects a push when another device already moved the save forward,
- keeps the last
KEEP_SNAPSHOTSsnapshots per game and deletes older archives, - protects every request with one shared token.
Install & run
Requires Node.js v24.2 or newer. The server runs the TypeScript source directly, without a build step.
git clone https://github.com/NYT92/vnsync.git
cd vnsync/server
npm install
cp .env.example .env # then set SECRET
npm start
Make a strong secret, for example with:
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
Then in the app on every device:
- Open Settings → Cloud & Storage Backend.
- Set Storage Backend Type to VNSync Server (Self-Hosted).
- Enter the Server URL, for example
http://192.168.1.10:3000. - Enter the
SECRETvalue as Token. - Click Test Connection, then Save Backend.
Other scripts: npm run dev restarts on file changes, npm test runs the server tests.
Configuration
Set these in server/.env:
| Variable | Default | Meaning |
|---|---|---|
SECRET | (required) | Token the app sends as Authorization: Bearer <SECRET>. The server does not start without it. |
PORT | 3000 | HTTP port. |
DATA_DIR | ./data | Folder for all saves. Back up this folder. |
KEEP_SNAPSHOTS | 20 | Snapshots kept per game. Older archives are deleted on push. |
MAX_UPLOAD_MB | 512 | Largest upload accepted. Bigger uploads get HTTP 413. |
Data layout inside DATA_DIR:
games/<game id>/head.json current head
games/<game id>/history.jsonl retained heads, oldest first
games/<game id>/snapshots/<id>.tar.zst save archives
library/catalog.json library backup
HTTPS & exposure
https:// URL in the app.Example with Caddy (gets a certificate automatically):
vnsync.example.com {
reverse_proxy 127.0.0.1:3000
}
If you use nginx, raise client_max_body_size to at least your MAX_UPLOAD_MB, or large saves fail.
Alternatives with no open port: a VPN such as Tailscale or WireGuard between your devices.
HTTP API
Every request needs Authorization: Bearer <SECRET>. Wrong token returns 401.
| Request | Purpose |
|---|---|
GET /api/ping | Health check. Returns {"ok":true}. |
GET /api/blob/<key> | Read a stored file. 404 when missing. |
PUT /api/blob/<key> | Write a file (atomic). For games/<id>/head.json, send If-Match: <expected head id> or If-None-Match: *. The server returns 412 when the current head is different. |
GET /api/games/<id>/history | Retained heads for a game, newest first. |
Quick check from a terminal:
curl -H "Authorization: Bearer $SECRET" http://192.168.1.10:3000/api/ping
Settings reference
General
- Device Name: shown on every snapshot.
- Max Local Vault Snapshots: snapshots kept per game on this device.
- Default Game Library Root Folder: where your games live on this device. VNSync uses it to find games whose path came from another PC. Remap User Paths applies it to existing games.
Automatic Sync Rules
- Pull latest saves on Game Launch: fast-forward pull before the game starts.
- Snapshot & Push on Game Exit: wait for the game to close, snapshot, and upload.
- Pre-Restore Safety Vault Backup: local snapshot before any overwrite. Keep this on.
System Tray & Window Behavior
- Hide to System Tray on Close: closing the window keeps VNSync running.
- Ask Before Closing: ask each time whether to minimize to tray or exit.
- Hide to System Tray on Minimize: minimize goes to the tray, not the taskbar.
Click Save Preferences after changes.
New PC & Steam Deck
- Install VNSync and configure the same storage backend.
- Set a new Device Name and the Default Game Library Root Folder for this device.
- Run Library Backup → Restore Library from Cloud.
- Run Auto-Fix Wrong User Paths. Fix any game that still shows Missing on this user/PC with Edit Paths.
- On Steam Deck / Linux with Proton, set each game's Wine / Proton Prefix. The prefix is in
~/.local/share/Steam/steamapps/compatdata/<app id>. For non-Steam games the app id is a large generated number; check the newest folder there after first launch. - Click Sync All.
Updates
Open About and click Check for Updates. VNSync compares your version with the latest GitHub release. New installers are on the releases page.
To update the server: git pull, then npm install in server/, then restart it. Your DATA_DIR is not touched.
Troubleshooting
| Problem | Fix |
|---|---|
| "Server rejected the token" | The Token in Settings does not match SECRET in server/.env. Copy it again; check for spaces. |
| "Remote saves changed during sync. Sync again." | Another device pushed while you synced. Click Sync Saves again; VNSync then pulls or shows a conflict. |
| "Server returned HTTP 413" | The save archive is bigger than MAX_UPLOAD_MB, or your reverse proxy body limit. Raise the limit. |
| Test Connection fails for the server | Check that the server runs, the port is open in the firewall, and the URL has http:// or https:// and the port. |
| Server exits with "SECRET is empty" | Set SECRET in server/.env. |
| "No local or remote save files found yet" | The save path rule points to an empty or wrong folder. Start the game, save once, and check the rule with Edit Paths. |
| Executable shows Missing on this user/PC | Run Auto-Fix Wrong User Paths, or select the executable in Edit Paths. |
| Steam Deck saves not found | Set the game's Wine / Proton Prefix. Without it, Windows tokens resolve to Linux paths. |
| "No remote library catalog backup found" | No device ran Backup Library to Cloud on this backend yet. |
Still stuck? Open an issue with your OS, engine, and the exact error message.