A personal-use Obsidian plugin that provides two-way sync between your vault and Google Drive or an S3 bucket. Works on desktop (macOS, Windows, Linux), Android, and iOS/iPadOS.
Note: This plugin was built for personal use. It is not published to the Obsidian community plugin directory. There is no warranty — use at your own risk. See LICENSE.
- Two-way sync between your Obsidian vault and a chosen Google Drive folder
- Cross-platform — works on desktop, Android, and iOS/iPadOS
- Automatic sync — syncs on file change (5s debounce), on a configurable interval, and/or on startup
- Manual sync — ribbon icon and command palette action
- Conflict resolution — when a file is modified both locally and on Drive, a modal shows all conflicts with per-file Local/Remote/Skip choices and bulk actions
- External merge tool support (desktop only) — configure a command like
bcomp {local} {remote}for Beyond Compare or any diff tool - Error reporting — failed files shown in a modal with retry option
- First sync wizard — choose Download from Drive, Upload to Drive, or Merge on first sync
- Self-updating — place new builds in a
.cloud-drive-syncfolder on Drive; the plugin checks for updates on startup and auto-reloads - Dotfile exclusion —
.obsidian,.trash, and all other dotfiles/dotfolders are automatically excluded from sync - Custom exclude patterns — glob patterns to skip additional files (e.g.
archive/**,*.tmp) - Provider abstraction — designed to support additional providers (Proton Drive planned)
- A Google account
- A Google Cloud project (free tier is sufficient)
- Go to Google Cloud Console
- Create a new project (e.g. "Obsidian Cloud Drive Sync")
- Enable the Google Drive API:
- Go to APIs & Services > Library
- Search for "Google Drive API"
- Click Enable
- Go to APIs & Services > OAuth consent screen (or Auth > Branding in the new UI)
- Set User Type to External
- Fill in the required fields (app name, user support email)
- Under Scopes (or Data Access in new UI), add:
https://www.googleapis.com/auth/drive - Under Audience (or Test users), add your Google email address
- Save — the app will be in "Testing" status, which is fine for personal use
- Go to APIs & Services > Credentials
- Click Create Credentials > OAuth client ID
- Application type: Web application
- Add an Authorized redirect URI:
https://cloud-drive-sync.pages.dev/ - Click Create
- Note the Client ID and Client Secret
git clone https://github.com/sm-merlot/cloud-drive-sync.git
cd cloud-drive-sync
npm install
npm run build:obsidianThis produces main.js in packages/obsidian-plugin/ and copies all plugin files (main.js, manifest.json, styles.css) to packages/obsidian-plugin/dist/ for easy deployment.
The plugin must be manually installed into each vault's .obsidian/plugins/cloud-drive-sync/ folder.
# Create the plugin folder
mkdir -p /path/to/your/vault/.obsidian/plugins/cloud-drive-sync
# Copy the plugin files from packages/obsidian-plugin/dist/
cp packages/obsidian-plugin/dist/* /path/to/your/vault/.obsidian/plugins/cloud-drive-sync/For development, symlink instead of copying:
ln -s /path/to/cloud-drive-sync/packages/obsidian-plugin/main.js /path/to/vault/.obsidian/plugins/cloud-drive-sync/main.js
ln -s /path/to/cloud-drive-sync/packages/obsidian-plugin/manifest.json /path/to/vault/.obsidian/plugins/cloud-drive-sync/manifest.json
ln -s /path/to/cloud-drive-sync/packages/obsidian-plugin/styles.css /path/to/vault/.obsidian/plugins/cloud-drive-sync/styles.cssThen run npm run dev --workspace=packages/obsidian-plugin for auto-rebuild on changes.
- Connect your device via USB or use a file manager app
- Navigate to your vault folder (usually in
Internal Storage/) - Create
.obsidian/plugins/cloud-drive-sync/if it doesn't exist - Copy
main.js,manifest.json, andstyles.cssinto that folder - Restart Obsidian
The .obsidian folder is hidden by default. You'll need a third-party file manager app (e.g. Santander) to access it:
- Locate your Obsidian vault in the file manager
- Navigate into
.obsidian/plugins/ - Create a
cloud-drive-syncfolder - Copy
main.jsandmanifest.jsoninto it - Restart Obsidian
After the initial install, the plugin can self-update from Google Drive — see Self-Updating below.
- Open Obsidian > Settings > Community Plugins > enable Cloud Drive Sync
- Go to the Cloud Drive Sync settings tab
- Enter your Client ID and Client Secret
- Click Open Google Auth — this opens your browser
- Sign in and authorize the app
- Copy the authorization code from the redirect page
- Paste the code into the Auth code field and click Submit
- Click Choose Folder to select which Google Drive folder to sync with
- Configure sync interval, startup sync, and exclude patterns as desired
To update the plugin on all devices without manual file copying:
- Build the plugin on your desktop:
npm run build:obsidian - In Google Drive, create a folder called
.cloud-drive-syncinside your sync root folder - Upload the contents of
packages/obsidian-plugin/dist/to that folder - On each device, the plugin checks this folder after every manual sync and on startup, auto-updating and reloading if files have changed
The .cloud-drive-sync folder is excluded from vault sync (dotfolder), so it only contains plugin build artifacts and won't appear in your vault.
The auto-updater compares MD5 hashes of the following files between your installed plugin and the Drive folder:
| File | Purpose |
|---|---|
main.js |
Plugin code |
manifest.json |
Plugin metadata/version |
styles.css |
Plugin styles |
If any file differs, all three are downloaded and the plugin reloads automatically.
- On startup — if "Sync on startup" is enabled
- After manual sync — clicking the status bar icon, ribbon icon, or using the command palette
- On demand — via command palette: Cloud Drive Sync: Check for plugin update
Auto-sync (interval and file watcher) does not check for updates to avoid unnecessary API calls.
- Ribbon icon (cloud icon) — triggers a full sync
- Command palette — "Cloud Drive Sync: Sync now" or "Cloud Drive Sync: Check for plugin update"
- Automatic — file changes are synced after 5 seconds of idle time; periodic full sync runs on the configured interval
On the first sync, a modal will ask you to choose a strategy:
- Download from Drive — treats Drive as the source of truth
- Upload to Drive — treats the local vault as the source of truth
- Merge — keeps both sides, prompts on conflicts
When a file is modified both locally and on Drive between syncs, a results modal appears showing all conflicts. For each file you can choose:
- Local — upload your local version to Drive
- Remote — download the Drive version
- Merge (desktop only) — opens an external merge tool
- Skip — leave the conflict unresolved for now
Bulk actions ("All Local", "All Remote") are available at the top.
The OAuth redirect page lives at docs/index.html and is hosted on Cloudflare Pages at https://cloud-drive-sync.pages.dev/.
It receives the ?code= parameter from Google after the user authorises the app, displays it, and auto-copies it to the clipboard so the user can paste it back into Obsidian.
- Edit
docs/index.html - Go to Cloudflare Pages → Workers & Pages → cloud-drive-sync
- Deployments → Upload assets (or push to the connected Git branch if using Git deploy)
- Upload the updated
docs/index.html
If the Cloudflare Pages URL ever changes:
- Update
REDIRECT_URIinpackages/obsidian-plugin/src/providers/google-drive/google-drive-auth.ts - Update the Authorized redirect URI in Google Cloud Console → APIs & Services → Credentials → your OAuth client
- Update this README
# Install dependencies (all workspaces)
npm install
# Build the Obsidian plugin for production
npm run build:obsidian
# Watch mode (auto-rebuild)
npm run dev --workspace=packages/obsidian-plugin
# Run all workspace tests
npm test
# Watch core package tests
npm run test:watch --workspace=packages/coreThis is an npm-workspaces monorepo. packages/core holds the framework-agnostic
sync logic (providers, sync engines, state store, utils) shared by every
consumer; packages/obsidian-plugin is the Obsidian plugin shell.
packages/
core/ # @cloud-drive-sync/core — no Obsidian dependency
src/
types.ts # Shared types and interfaces
index.ts # Public barrel export
providers/
cloud-provider.ts # Abstract provider interface
s3/
s3-api.ts # S3 REST client (SigV4 via Web Crypto)
s3-provider.ts # CloudProvider implementation
sync/
sync-state.ts # Per-file tracking database
mirror-sync-engine.ts # Existence-only bidirectional mirror (no content-conflict handling — for write-once files)
http/
http-client.ts # HttpClient port — host shell supplies the transport (CORS bypass)
fs/
local-file-system.ts # LocalFileSystem port — host shell supplies real filesystem access
util/
hash.ts # MD5 implementation
path.ts # Path helpers, glob matching
merge.ts # 2-way line merge (used by the Obsidian plugin's full SyncEngine)
tests/
obsidian-plugin/ # Obsidian plugin shell
manifest.json / versions.json / styles.css / esbuild.config.mjs
src/
main.ts # Plugin entry point
settings.ts # Settings tab UI
http/
obsidian-http-client.ts # HttpClient impl: Node https (desktop) / requestUrl (mobile)
providers/google-drive/ # Google Drive provider (Obsidian-only — requestUrl-based, not shared)
sync/
sync-engine.ts # Full bidirectional sync engine w/ content-conflict handling
sync-state.ts / *-modal.ts # Conflict/first-sync/results modals (Obsidian Modal UI)
docs/
index.html # Cloudflare Pages OAuth redirect (https://cloud-drive-sync.pages.dev/)
MIT — see LICENSE.