Vault synchronization and scheduled backups across devices using S3-compatible storage (AWS S3, Cloudflare R2, RustFS, etc.) with optional end-to-end encryption.
Vault synchronization and scheduled backups across devices using S3-compatible storage (AWS S3, Cloudflare R2, RustFS, etc.) with optional end-to-end encryption.
LOCAL_ and REMOTE_ copies so you never lose data.main.js, manifest.json, and styles.css from the latest release.<VaultPath>/.obsidian/plugins/simple-storage-sync-and-backup/auto for Cloudflare R2.vault) — this is the S3 folder where your files live.backups).⚠️ Important: If you enable encryption, you MUST remember your passphrase. There is no recovery if it is lost.
When encryption is enabled:
The plugin is a sync and backup tool, so by design it enumerates every file in your vault and then reads / uploads / downloads the files inside your configured sync and backup scope. This section spells out exactly what each piece of the plugin touches so you can make an informed decision before enabling it.
| API | Why the plugin uses it |
|---|---|
vault.getFiles() |
Enumerates every file in the vault during sync planning and during backup snapshots. Without this the plugin cannot know what to sync or back up. |
vault.read() / vault.readBinary() |
Reads file content so it can be uploaded to S3. Triggered only for files inside the sync/backup scope (every vault file minus your Exclude patterns minus the plugin's own settings directory). |
vault.on('create' / 'modify' / 'delete' / 'rename') |
Tracks which files changed since the last sync so the next cycle only re-checks dirty paths. |
| Bulk re-read on encryption toggle | When you enable, disable, or rotate the passphrase, the plugin reads every in-scope vault file and re-uploads it in the new payload format. |
| Destination | What ends up there |
|---|---|
S3 (under your configured sync prefix, default vault) |
A copy of every vault file inside the sync scope. File payloads are end-to-end encrypted when Enable encryption is on; plain otherwise. |
S3 (under your configured backup prefix, default backups) |
Timestamped full-vault snapshots. File payloads are encrypted when encryption is enabled; the per-snapshot .backup-manifest.json is always plaintext so the plugin can list and inspect backups without the passphrase (it contains file paths, sizes, SHA-256 checksums, the encryption flag, and the originating device ID). |
Local vault (vault.create / vault.modify / vault.createBinary / vault.modifyBinary / vault.rename / vault.createFolder) |
Files downloaded from S3 on the receiving end of a sync, plus LOCAL_* / REMOTE_* conflict artifacts when a file diverged on two devices. Parent folders are auto-created top-down as needed; the rename API is used to stage LOCAL_* conflict copies. |
Local vault trash (via fileManager.trashFile) |
Files that were deleted on another device and propagated by sync. Honours Obsidian's Files and Links → Deleted files preference (system trash vs. .trash/ folder vs. permanent). |
IndexedDB (database obsidian-s3-sync-journal-{vaultName}) |
Per-file sync baselines (path, hash, size, mtime, ETag) used for three-way reconciliation, plus a destination fingerprint that detects when you reconnect to a different bucket/prefix. Vault-scoped so two vaults on the same device never share state. |
Obsidian vault-scoped storage (key s3-sync-device-id) |
A randomly generated per-vault device identifier. The same ID is written into every uploaded S3 object's obsidian-device-id custom metadata for last-writer attribution, and into the deviceId field of every backup manifest. |
data.json (Obsidian plugin settings) |
All plugin settings (S3 credentials, optional saved passphrase, sync/backup toggles, exclude patterns) plus the last-completed backup timestamp used by the scheduler. The plugin's own settings directory is hardcoded-excluded from sync so this file never leaves your device. |
http://localhost:9000 for a local RustFS).Important — Obsidian config files are in scope by default. Only the plugin's own settings directory (
.obsidian/plugins/simple-storage-sync-and-backup/) is hard-excluded. Other files under.obsidian/(workspace layout, hotkeys, third-party plugin settings, etc.) are vault files from Obsidian's point of view and are enumerated and synced unless you add them to Exclude patterns in settings. If you do not want those propagated across devices, add patterns such as.obsidian/workspace*,.obsidian/hotkeys.json,.obsidian/plugins/**, etc. The defaults (**/workspace*,.trash/**) cover the workspace layout but not other config files.
| Setting | Description |
|---|---|
| Provider | Storage provider: AWS S3, Cloudflare R2, RustFS, or Other S3-compatible. |
| Endpoint URL | S3-compatible endpoint URL. Required for non-AWS providers (e.g., https://<ACCOUNT_ID>.r2.cloudflarestorage.com for R2, http://localhost:9000 for RustFS). Hidden when provider is AWS. |
| Region | AWS region (e.g., us-east-1). Use auto for Cloudflare R2. |
| Bucket | Name of your S3 bucket. |
| Access key ID | Your S3 access key ID. Displayed as a password field. |
| Secret access key | Your S3 secret access key. Displayed as a password field. |
| Force path style | Use path-style URLs instead of virtual-hosted. Required for some self-hosted S3-compatible endpoints. Only shown for the Other S3-compatible provider — AWS, R2, and RustFS each pin a fixed addressing mode internally. |
| Test connection | Verify credentials, bucket access, and required permissions. |
| Setting | Description |
|---|---|
| Enable end-to-end encryption | Encrypt all files with XSalsa20-Poly1305 before uploading to S3. Requires a passphrase (minimum 8 characters). Shows a strength indicator while typing. |
| Remember passphrase | Save the passphrase locally so the vault unlocks automatically on startup. The passphrase is stored in the plugin's data.json, which is hardcoded-excluded from sync. |
| Unlock | When the vault is encrypted but locked (e.g., after restarting Obsidian without "Remember passphrase"), enter your passphrase to unlock sync and backup. |
| Disable encryption | Re-upload all files as plaintext and remove the encryption marker. Shows a confirmation dialog. Other devices switch to plaintext mode automatically on next sync. |
| Setting | Description | Default |
|---|---|---|
| Enable sync | Master switch for bi-directional vault synchronization. | On |
| Sync prefix | S3 folder path for synced files (e.g., vault → s3://bucket/vault/). |
vault |
| Auto-sync | Automatically sync at regular intervals. | On |
| Sync interval | How often to auto-sync. Options: 1, 2, 5, 10, 15, or 30 minutes. Only shown when auto-sync is enabled. | 5 min |
| Sync on startup | Run a sync immediately when Obsidian starts. | On |
| Setting | Description | Default |
|---|---|---|
| Enable backups | Master switch for scheduled vault backup snapshots. | On |
| Backup prefix | S3 folder path for backups (e.g., backups → s3://bucket/backups/). |
backups |
| Backup interval | How often to create snapshots. Options: every hour, 6 hours, 12 hours, daily, every 3 days, or weekly. | Daily |
| Enable retention | Automatically delete old backups based on the retention policy. | Off |
| Retention mode | How to determine which backups to keep: By days (delete backups older than N days) or By copies (keep only the latest N backups). Only shown when retention is enabled. | By copies |
| Retention days | Delete backups older than this many days (1–360). Only shown in "By days" mode. | 30 |
| Retention copies | Keep only the latest N backups (1–1000). Only shown in "By copies" mode. | 30 |
| Backup now | Create a backup snapshot immediately. | |
| View backups | Open a modal listing the 5 most recent backups with per-backup download buttons. Each entry shows timestamp, file count, size, and encryption status. |
| Setting | Description | Default |
|---|---|---|
| Debug logging | Enable verbose console logging for troubleshooting. | Off |
| Exclude patterns | Comma-separated glob patterns for files/folders to exclude from sync (e.g., workspace*, .trash/*). The plugin's own settings directory is always excluded regardless of this setting. |
**/workspace*, .trash/** |
| Reset to defaults | Reset all settings to defaults, preserving S3 connection credentials. Shows a confirmation dialog. |
All commands are available via the Obsidian command palette (Ctrl/Cmd + P) and can be bound to custom hotkeys.
| Command | Description |
|---|---|
| S3 Sync + Backup: Sync now | Trigger an immediate sync. |
| S3 Sync + Backup: Backup now | Trigger an immediate backup snapshot. |
| S3 Sync + Backup: Pause sync | Pause automatic sync (shown only when sync and auto-sync are enabled). |
| S3 Sync + Backup: Resume sync | Resume automatic sync after pausing. |
| S3 Sync + Backup: View sync log | Open the sync log viewer. |
| S3 Sync + Backup: View backups | Open a modal listing recent backups with download buttons. |
| S3 Sync + Backup: Open settings | Open the plugin settings page. |
This plugin is designed for multi-device use. Each device gets a unique ID on first run, and all S3 uploads are tagged with the writing device's ID.
How it works:
LOCAL_ and REMOTE_ copies of the file.Encryption across devices:
your-bucket/
├── vault/ # LIVE DATA (synced)
│ ├── .obsidian-s3-sync/
│ │ └── .vault.enc # Encryption marker (if enabled)
│ ├── Notes/
│ │ └── my-note.md
│ └── Attachments/
│ └── image.png
│
└── backups/ # SNAPSHOTS (read-only)
├── backup-2024-12-25T14-30-00/
│ ├── .backup-manifest.json # Plain JSON: file count, checksums, encrypted flag
│ └── ... (full vault copy)
└── backup-2024-12-24T14-30-00/
Note: The plugin's own settings directory (
.obsidian/plugins/simple-storage-sync-and-backup/) is never uploaded to S3, regardless of exclude pattern configuration.
data.json, which is hardcoded-excluded from sync to prevent leakage.The plugin includes 565+ automated tests: unit tests covering sync, encryption, backup, and utility modules, pipeline end-to-end tests, and integration tests against live S3 endpoints. CI runs linting, type-checking, and the full test suite on every pull request.
LOCAL_ and REMOTE_ copies. The conflict resolves on the next sync.
.backup-manifest.json) is always plain JSON so the plugin can read backup metadata, but it contains only file names, checksums, and the encrypted flag — no file content.
**/workspace* and .trash/** are excluded. You can customize this in Settings → Advanced → Exclude patterns. The plugin's own settings directory (.obsidian/plugins/simple-storage-sync-and-backup/) is always excluded and cannot be overridden.
MIT © Ceilão Labs
Made with love for the Obsidian community