Bundles
Bundles pack many small files into a single Walrus blob (a Walrus Quilt) instead of writing each file separately. One on-chain transaction covers the whole batch — gas drops by up to ~238× and per-byte storage cost drops by up to ~400× on small files. Individual files remain independently readable.
When bundles are used
Section titled “When bundles are used”There are two modes. You don’t choose between them directly — they’re selected by plan and upload method.
| Mode | Who uses it | Trigger | Timing |
|---|---|---|---|
| PPU batch | Pay-per-upload users | ”Bundle files” toggle in the upload UI (or SDK batch endpoints) | Quilt built immediately on confirm |
| Subscription auto-batching | Developer / Scale / Enterprise | Automatic for files under 10 MB | Flushed when total pending ≥ 100 MB or oldest pending > 1 hour |
Files ≥ 10 MB always go through the single-file Walrus sync path; they get less benefit from batching and don’t have to wait for flush.
PPU batch uploads (opt-in)
Section titled “PPU batch uploads (opt-in)”When a PPU user selects 2+ files in the web uploader, the Bundle files toggle appears. It defaults to on.
With bundling on:
- One aggregated cost quote instead of one per file
- One Sui payment covers all files in the batch
- Files are uploaded to the hot cache in parallel via presigned URLs
- A single
walrus-quilt-syncjob writes the quilt after confirm
With bundling off, each file goes through the normal single-file PPU flow (one quote, one payment, one Walrus write per file).
Shared vaults
Section titled “Shared vaults”Bundles work for both public and SEAL-encrypted shared vaults. Each file is SEAL-encrypted client-side with its own nonce before being added to the batch — the quilt just happens to contain ciphertext blobs. Encryption and bundling are independent.
API shape
Section titled “API shape”If you’re building your own client, the PPU batch flow uses two endpoints instead of /api/files/upload + /api/files/:id/confirm:
# 1. Request batch quote / presigned URLsPOST /api/files/batch-upload{ "vaultId": "<vault-uuid>", "epochs": 5, "files": [ { "name": "a.txt", "mimeType": "text/plain", "sizeBytes": 1200 }, { "name": "b.txt", "mimeType": "text/plain", "sizeBytes": 3400 } ]}# First call returns 402 with a single quote covering the whole batch.# Retry the same request with { quoteId, txDigest } after paying.# Successful response: { quiltId, files: [{ fileId, uploadUrl, spacesKey, name }, ...] }
# 2. PUT each file to its uploadUrl in parallel.
# 3. Confirm the batch as a wholePOST /api/files/batch-confirm{ "quiltId": "<quilt-uuid>" }Subscription auto-batching (automatic)
Section titled “Subscription auto-batching (automatic)”Subscription users don’t see bundles as a setting. Files under 10 MB are marked as pending quilting when confirmed. A flush job runs every 5 minutes and creates a quilt when either condition holds:
- total pending size ≥ 100 MB, or
- oldest pending file > 1 hour old
Files from different users can share a quilt — they’re already encrypted client-side for shared vaults, so there’s no privacy impact. Quilts are grouped by epoch duration so every file in a quilt shares one expiry.
Constraints
Section titled “Constraints”Quilts are a Walrus protocol feature, and inherit its limits:
| Limit | Value |
|---|---|
| Max files per quilt | 666 |
| Max quilt size | ~100 MB |
| Mutability | Immutable — individual files can’t be removed, extended, or renewed separately |
| Per-file identifier | QuiltPatchId (not the usual BlobId) |
On the files record, quilted files have walrusBlobId / walrusBlobObjectId null. Instead, look at:
quiltId— which quilt the file belongs toquiltPatchId— patch identifier within the quilt, used to read the file- the parent
quiltsrecord — holds the actualwalrusBlobIdandwalrusBlobObjectIdused for the whole batch’s epoch renewals
Downloads work the same: the API looks up the patch automatically, so GET /api/files/:id/download and opentusk download <file-id> behave identically to single-blob files.
Renewal and cancellation
Section titled “Renewal and cancellation”Epoch renewal is quilt-level, not file-level. At renewal time:
- All files still active — the quilt is renewed with
extendBlob. - Some files cancelled or expired — active files are pulled back into the pending pool and re-quilted into a new batch; the old quilt is allowed to expire.
- All files cancelled — the quilt expires.
Non-quilted files continue to renew individually.
Cost impact
Section titled “Cost impact”| Component | Single-file | Quilt batch |
|---|---|---|
| Walrus write fee | N × per-file | 1 × on total size |
| Walrus storage | N × per-file overhead | 1 × aggregate |
| Sui gas | N × ~0.005 SUI | 1 × ~0.005 SUI |
| Platform margin | per-file | applied once on batch total |
For PPU users, the saving is reflected directly in the 402 quote. For subscription users, there is no user-facing price change — the platform absorbs the Walrus/gas savings.