uppinote202k downloadsTwo-way sync between Obsidian and your databases — Airtable, SeaTable, Supabase, Notion. Multi-config, conflict resolution, computed fields, Notion page-body pull.
Two-way sync between your databases and your Obsidian vault. Point it at Airtable, SeaTable, Supabase, or Notion — it pulls rows in as notes, pushes your edits back, and keeps computed fields fresh.
| Provider | Pull → notes | Push edits back | Computed fields | Page body |
|---|---|---|---|---|
| Airtable | ✅ | ✅ | ✅ formula / rollup / lookup | — |
| SeaTable | ✅ | ✅ | ✅ formula / link-formula | — |
| Supabase | ✅ | ✅ | ✅ generated columns | — |
| Notion | ✅ | ✅ page properties | ✅ formula / rollup | ✅ blocks → Markdown (pull) |
Built on a provider-agnostic core — every provider gets the same multi-config, conflict-resolution, and safety machinery.

Manual / Obsidian wins / Remote wins, and auto-refetch server-computed values after a push{{field}} templates (incl. {{body}} for Notion page content), subfolder organization by field value, Bases-friendly YAML frontmatterThe 3-step shape is the same for every provider: get a token → add a credential → pick table & folder. Expand yours:
data.records:read (import) · data.records:write (bidirectional) · schema.bases:read (field pickers)https://cloud.seatable.io unless self-hosted)sb_publishable_…) recommended; legacy anon JWT also works; secret/service_role bypasses RLS (the plugin auto-detects and warns)public already is)SECURITY DEFINER SQL function — Copy SQL → run it in the Supabase SQL Editor → Verify. Saving is blocked until verified (fail-closed); anon/secret keys skip this entirely.ntn_…)Then set the destination folder, an optional template, and toggle bidirectional sync if you want edits flowing back. Multiple configurations switch via the tab bar at the top of the settings panel.
Every command is labeled with the active config's provider (Ctrl/Cmd + P):
| Command | Description |
|---|---|
| Sync current note from {provider} | Refresh the active note from the remote |
| Sync all notes from {provider} | Import / update everything |
| Sync current / modified / all to {provider} * | Push local frontmatter edits |
| Bidirectional sync current / modified / all * | Push → wait for formulas → pull computed values |
* Hidden unless Enable bidirectional sync is on. Scheduling: Sync interval (minutes, 0 = manual) and Watch for changes (queue a sync when a note is edited).
| Setting | Description |
|---|---|
| Credential | Pick a registered credential (any provider) |
| Base / Table / View | Provider-aware pickers (Airtable Meta API · SeaTable metadata · Supabase OpenAPI · Notion data sources) |
| Filename field | Field used for note filenames — only name-safe types are offered |
| Subfolder field | Optional — organize notes into destination/value/ subfolders |
| New file location | Destination folder in your vault |
| Template file | Optional {{field}} template |
| Sync interval | Auto-sync frequency in minutes (0 = disabled) |
| Allow overwrite | Update existing notes vs skip duplicates |
| Sync page body (Notion) | Pull the page's block content into the note body — pull-only, overwrites local body edits |
| Setting | Description |
|---|---|
| Enable bidirectional sync | Allow Obsidian → remote pushes |
| Conflict resolution | Manual (notify & skip) · Obsidian wins · Remote wins |
| Watch for file changes | Auto-queue a push when a synced note is edited |
| Auto-sync computed fields | After pushing, pull back formulas / rollups / generated columns |
| Computed-field sync delay | ms to wait for the remote to recompute (default 1500) |
Each provider's native types map to a normalized taxonomy (text / number / date / boolean / single-select / multi-select / attachment / link / computed / system). Read-only and object-shaped types are excluded from pushes automatically — fail-closed for anything unknown.
Airtable — filename-safe: singleLineText, singleSelect, number, formula · read-only: formula, rollup, count, lookup, externalSyncSource, aiText, button, createdTime, lastModifiedTime, createdBy, lastModifiedBy, autoNumber · full reference →
SeaTable — filename-safe: text, single-select, number, auto-number, formula · read-only: formula, link-formula, button, ctime, mtime, creator, last-modifier, auto-number · never pushed (object-shaped): collaborator, geolocation, file, digital-sign, link
Supabase — filename-safe: string, string:uuid, integer (+ :readonly variants) · read-only: anything the PostgREST spec flags readOnly (generated columns, view columns) · mapping: text/uuid → text, integer/numeric → number, boolean → boolean, date/timestamptz → date, json(b) → text, arrays → multi-select
Notion — filename-safe: title, select, status, number, email, phone_number, unique_id · read-only: formula, rollup, created_time/by, last_edited_time/by, unique_id, button · pushable: title, rich_text, number, checkbox, select, status, multi_select, date, url, email, phone_number (object-valued ones are rebuilt into the API shape on push) · never pushed: people, files, relation
flowchart LR
O[Obsidian notes] -- "push writable fields" --> R[(Remote DB)]
R -- "computes formulas / rollups" --> R
R -- "pull rows + computed values" --> O
R -- "Notion blocks → Markdown body (pull-only)" --> O
primaryField frontmatter — the immutable handle for matchingdestination/field-value/note.md, nested paths supported, duplicates detected recursivelyManual notifies and skips the field)---
title: "{{Title}}"
status: "{{Status}}"
created: "{{Created time}}"
---
# {{Title}}
{{body}} <!-- Notion page content (when Sync page body is on) -->
## Attachments
{{Attachment.0.url}}
{{Attachment.0.url}}, {{User.name}} · {{body}}: the fetched Notion page body (a real field named body wins, for backward compatibility)Frontmatter is emitted with Bases-friendly YAML types — import a folder, point the Bases plugin at it, and edit your database in table/card views.
Nothing is sent anywhere except the database APIs you configure; there is no telemetry.
vault.getAllLoadedFiles, getAbstractFileByPath) — find notes to sync and power folder/file autocomplete. Paths only; contents are read on demand by the sync flow.read, create, modify, createFolder, adapter.exists) — import records to .md, parse frontmatter for pushes, write computed values. Scoped to your configured destination folders.vault.on) — detect edits for Watch for changes; the handler filters to your destination folder before queuing.navigator.clipboard.writeText) — only the Supabase "Copy SQL" button; clipboard is never read.atob) — locally decodes the pasted Supabase key's JWT payload to auto-detect its kind and show the right RLS warning; never stored or transmitted.requestUrl) — REST calls to Airtable / SeaTable / Supabase / Notion only, using credentials you registered. No third-party services, no analytics, no update checks.| Symptom | Check |
|---|---|
| No fields in dropdowns | Token permissions/scopes; base & table selection |
| Notion: "0 data sources shared" | Share the database with your integration: ⋯ → Connections in Notion |
| Bidirectional not working | Write permission (Airtable data.records:write · SeaTable "Read and write" token) |
| Formulas not updating after push | Increase Computed-field sync delay |
| Supabase: empty results / RLS denial | Your key respects RLS — add SELECT/INSERT/UPDATE policies for the table |
| Notion body slow on big pages | Body fetching is rate-limited (~3 req/s) with a per-note request budget; very deep pages get a truncation marker |
| Filename errors | The chosen field's type must be in the provider's name-safe list |
| Local body edits disappear (Notion) | By design in v1 — body is pull-only and Notion wins; keep local prose outside synced folders |
Contributor docs (e2e suites, Supabase demo schema, Notion test setup): tests/e2e/README.md
If this plugin is useful to you:
MIT