split cuts the final archive into fixed-size parts before upload. snapr applies it after compression and (if configured) encryption, so each part is a slice of the encrypted, compressed bytes — not a self-contained mini-archive.
Use it when:
- a storage backend rejects objects above some size (FTP/SFTP server quotas, email attachment limits, providers without S3 multipart upload),
- you want backups to fit on removable media of a known capacity,
- a flaky network makes re-uploading one failed part cheaper than re-uploading the whole archive.
Fields
Example
snapr.yaml
How parts are named
Each part gets the original archive name plus a.part- suffix with three lowercase letters, counting in base 26: aaa, aab, … zzz. That caps an archive at 17,576 parts. With a 1 GiB chunk that is a 17.1 TiB ceiling — raise chunkSize if you ever get close.
On-disk layout
A split snapshot lives in a wrapper directory inside the per-job folder. Parts are plain files inside it:.parts-3-3221225472 means 3 parts, about 3 GiB). snapr reads both from the directory name alone, so listing a job’s backups never descends into the wrapper or stats individual parts — it stays one storage call regardless of part count.
The wrapper is created at upload time and never modified afterward. Retention keeps the whole wrapper or deletes it entirely.
If the archive fits in a single chunk, snapr skips the wrapper and uploads the single part (still named
.part-aaa)
directly into the job folder. A wrapper with one part is never produced.Retention treats a set as one backup
One wrapper directory counts as one logical backup.retention.last: 14 keeps the 14 newest snapshots, no matter how many parts each produced. Rotation removes the wrapper and all its parts in one operation.
Downloading a split backup
The web UI andGET /api/v1/jobs/{name}/backups/{filename}/download accept the set ID — the original archive name without the wrapper suffix and without .part-XXX. snapr opens each part on the storage, streams them back-to-back, and serves the result as one continuous download. You get a single file, no manual concatenation.
The UI also offers per-part download, useful when one full-archive transfer is impractical.
For bunny.net Storage behind a signed Pull Zone, full-set download is not supported — one HTTP redirect cannot
represent N parts. “Download all” returns
501 Not Implemented there. Per-part download still works, since each part
gets its own redirect to a signed URL. For full-set streaming, use a non-redirect storage (Local, S3, SFTP, WebDAV) as
the download source.Reassembling parts manually
If you copy a wrapper directory off the storage yourself, concatenate the parts in lexicographic order.1
Concatenate the parts
The
aaa, aab, aac suffixes sort lexicographically in write order, and shell globs expand in the same order, so a plain cat is safe:2
Decrypt (if the job uses encryption)
3
Extract
Toggling split on or off
Adding or removing thesplit block between runs is safe. Existing snapshots keep their layout — wrapper directories from past split runs and plain archives from non-split runs coexist in the same job folder. Listing, retention, and download handle both transparently.
Notes
chunkSizeis validated at config load. An unparseable value fails startup with a validation error.- Splitting runs purely in Go — no external
splitbinary required. - A part smaller than
chunkSizeis always the last part. Don’t estimatechunkSizefrom an arbitrary part’s size.