Skip to content

Sync

Weft syncs your vault through object storage you own, end-to-end encrypted. There is no Weft server and no Weft account. The bucket holds only ciphertext; the key that decrypts it never leaves your devices.

Your notes are plain .html files. Sync should keep them clean and keep you in control of where they live. So Weft makes two choices:

  • Own your storage — You point Weft at a bucket you control. Cloudflare R2 by default (zero egress), or AWS S3, Backblaze B2, Google Cloud Storage, MinIO, or any S3-compatible storage. Weft runs no server in the middle.
  • Zero-knowledge cloud — Everything written to the bucket is sealed with XChaCha20-Poly1305. The cloud sees only ciphertext and can decrypt nothing. Your storage credentials decrypt nothing either.
GuaranteeHow
End-to-end encryptionOne vault key, generated on your device and never uploaded. Blobs and manifests are sealed with XChaCha20-Poly1305 before they touch the bucket.
No silent data lossFile-level sync with version vectors (clock-independent). When two devices change the same note concurrently, the result is a conflict-copy, never an overwrite.
Deletes are recoverableA deletion during sync moves the note to a .trash folder rather than removing it. Nothing is ever gone.
Integrity vs a malicious cloudA per-device Ed25519-signed HEAD is bound to the manifest by hash, alongside a sealed device registry and rollback detection. The cloud cannot forge, splice, or silently roll back your history.

Choose a provider with --provider. R2 is the default; S3, B2, MinIO, and any S3-compatible bucket work the same way.

ProviderFlagNotes
Cloudflare R2--provider r2Default. Zero egress fees.
AWS S3--provider awsUse --region.
Backblaze B2--provider b2S3-compatible endpoint.
MinIO / self-host--provider minioSet --endpoint and often --path-style.
Local filesystem--provider fsFor testing; set --fs-path.

First, validate your bucket credentials and connectivity. This touches no data and writes nothing.

Terminal window
# verify creds + connectivity before writing anything
weft sync check --provider r2 \
--endpoint https://<account>.r2.cloudflarestorage.com \
--bucket my-weft-vault \
--access-key <key> --secret <secret>

Once check passes, initialize sync on this first device. This generates the vault key locally, seals the device registry, and does the first push.

Terminal window
# R2 example — sets up E2EE sync on your own bucket
weft sync init --provider r2 \
--endpoint https://<account>.r2.cloudflarestorage.com \
--bucket my-weft-vault \
--access-key <key> --secret <secret>

When the daemon is running, editing syncs automatically — there is nothing to remember.

Terminal window
# the daemon converges in the background while it runs
weft serve ~/notes

If the daemon is not running, run one convergence cycle by hand. It pushes local changes and pulls remote ones in a single pass.

Terminal window
# one push + pull cycle
weft sync

Print the vault’s 24-word recovery phrase and keep it somewhere safe. If you ever lose every device, it rebuilds the vault from the bucket.

Terminal window
# print the 24-word phrase
weft sync recovery
# rebuild a vault from the phrase
weft sync recover --phrase "word1 word2 ... word24"

You do not enroll the second device here. Pairing hands the vault key device-to-device — resistant to a man-in-the-middle, even the cloud — without retyping a passphrase. See Devices for weft sync pair, weft sync pair-approve, and the passphrase-based weft sync join.