Archive Format
Every SaveVault backup is a standard compressed archive you can open with any tool, and every one carries enough information to restore it without SaveVault installed. This page is the user-facing summary of the format; the normative spec and the code that writes it live in the app repository.
Guarantees
Section titled “Guarantees”- Single-game. One archive holds exactly one game’s files.
- Self-describing. Every archive embeds
savevault-manifest.json(machine-readable index) andREADME.txt(human restore instructions). Neither SaveVault’s database nor the filename is needed to restore. - Atomic. Archives are written to
<name>.partand renamed on success, so a file with an archive extension is never half-written. - Portable. File paths are stored under placeholder tokens that a restore re-resolves against the destination machine.
Naming
Section titled “Naming”<SanitizedGameTitle>_<YYYY-MM-DD_HH.MM.SS>_<device-tag>.<ext>The timestamp is local time on the source machine; the manifest’s created_at (UTC) is
the authoritative creation time. The device tag is the writing device’s name, lowercased
with punctuation turned into -, plus the first four characters of its id — for example
steam-deck-oled-3f9a — so devices sharing one folder never write the same filename in
the same second. Archives from older versions or other tools omit the tag. A second
backup of one game on one device within the same second gets a -2, -3… suffix; an
existing archive is never replaced.
Title sanitization is lossy, so the filename is not an identity — always trust the
manifest. Pre-restore safety backups use <Title>_pre-restore_<timestamp>[_<device-tag>][-N].<ext>
(-N is the same collision suffix, -2, -3…); the _pre-restore_ marker is how SaveVault keeps them from ever counting as “the latest
backup”. Live snapshots live under <backup_dir>/snapshots/<Game>/.
Formats
Section titled “Formats”| Written | Also accepted on read |
|---|---|
.zip (default), .tar.gz, .tar.zst |
.tgz, .tar.zstd |
Zip entries opt into Zip64, so single files over 4 GiB are supported. Entry paths always use forward slashes. Symlinks are never written and are skipped on extraction.
Layout
Section titled “Layout”<Slug>_<timestamp>_<device-tag>.<ext>├── README.txt # human restore instructions├── savevault-manifest.json # machine-readable index├── data/│ ├── saves/<placeholder>/<original-tail>/...│ └── configs/<placeholder>/<original-tail>/...└── registry/ ├── windows/<saves|configs|shared>/<sanitized-key>.reg └── proton/<appid>/<saves|configs>/<hive-file> # e.g. user.regSaves and configs are kept apart so a restore can bring back one without the other
(--include saves|configs|both). Windows registry exports are plain .reg files;
Proton hives keep their original names.
Placeholder tokens
Section titled “Placeholder tokens”The first segment after data/saves/ or data/configs/ names the well-known directory
the files came from. Restore resolves it on the destination machine, which is why a
backup taken under one user profile restores cleanly under another.
| Token | Windows | Linux / macOS |
|---|---|---|
appData |
%APPDATA% |
$XDG_CONFIG_HOME (~/.config) |
localAppData |
%LOCALAPPDATA% |
$XDG_DATA_HOME (~/.local/share) |
localAppDataLow |
%USERPROFILE%\AppData\LocalLow |
— (except a Unity <Company>/<Product> folder, which maps into the game’s Steam Android container on a Steam Frame) |
documents |
%USERPROFILE%\Documents |
~/Documents |
savedGames |
%USERPROFILE%\Saved Games |
— |
home |
%USERPROFILE% |
~ |
publicDir |
%PUBLIC% |
— |
programData |
%ProgramData% |
— |
winDir |
%SystemRoot% |
— |
winDrive |
winDrive/c/Games/X → C:\Games\X |
— |
xdgConfig |
%APPDATA% |
$XDG_CONFIG_HOME |
xdgData |
%LOCALAPPDATA% |
$XDG_DATA_HOME |
gameInstall |
the game’s install directory | same |
absolute |
no standard directory matched; the literal source path is in the manifest | same |
A token marked — is unresolvable on that OS. Restore then skips that root with an
explanatory note rather than guessing; you can --remap-root it, opt in to
--cross-platform, or use --redirect-wine to send it into a Proton prefix.
The manifest
Section titled “The manifest”savevault-manifest.json records the producer version, creation time, source platform,
the game’s identity (name, Steam id, cloud providers, install hint), one entry per
root (id, kind, placeholder, original absolute and portable paths), and one entry per
file (root, in-archive path, relative path, size, BLAKE3 hash, modification time),
plus any registry rows, pin state, and label.
Three optional fields support multiple devices sharing a
folder. source_device holds the writing device’s id (random, generated once per
install) and display name. archive_id is a random id for this archive, and based_on
is the archive_id the saves descended from — the archive the device last restored, or
its own previous backup. Following based_on links is how SaveVault tells whether the
newest backup includes another device’s progress. Other tools producing archives should
omit source_device and based_on rather than invent values.
Restore verifies each file’s BLAKE3 hash before writing it and restores modification
times. savevault-cli verify checks the whole archive against these hashes at any time.
Root ids are what restore --remap-root <id>=<path> refers to; explain prints them.
Pre-restore safety archives also carry an undo_delete list: files the guarded restore
created, each with its hash. Restoring the safety archive deletes those files — but
only while their bytes still match, so a save you progressed since is never deleted.
Restoring by hand
Section titled “Restoring by hand”Extract the archive and follow README.txt inside it. It maps each placeholder folder
to the real directory on each OS and includes copy-paste PowerShell and bash commands
plus registry import steps. That file is generated by the same code that writes the
archive, so it’s always accurate for the archive it ships in.
Adoption of external archives
Section titled “Adoption of external archives”SaveVault treats the backup folder as the source of truth. Any file at the top level of
backup_dir (subfolders aren’t scanned) is adopted into the library automatically when
its extension is one of the accepted formats and savevault-manifest.json parses from
the archive root. Adopted archives take their game name, creation time, pin state,
label, and source device from the manifest. Retention is counted per device: each device
prunes only the archives it wrote plus unattributed ones, never another device’s.
This is how backups copied from another machine, pulled down by cloud sync, or produced
by third-party converters show up in SaveVault with no import step. If you produce
archives yourself, preserve the original backup time in created_at (retention orders
by it), write atomically under a non-archive name and rename, and include README.txt
(explain requires it).
Reserved files in the backup folder
Section titled “Reserved files in the backup folder”| Name | Meaning |
|---|---|
.savevault-check-access |
rclone bisync access marker — never delete. |
.savevault-scheduled-running |
A scheduled pass is mid-flight. |
*.part |
An archive being written; ignored by the library. |
.sv-manifest-*.zip |
Pin/label metadata repack in progress. |
.savevault-manifest-*.json, .savevault-readme-*.txt |
Per-backup staging temps (the manifest and README being built); not part of the pin/label repack. |
snapshots/ |
Live Protection snapshots, with their own index. Device-local: excluded from cloud sync. |
*.enc |
Reserved extension. SaveVault never produces it, and any library rows for it are dropped; don’t create files with it. |