I keep my project tracker in Notion and my actual thinking in Obsidian. After three years of moving between the two, that split is the only sane answer I have to "which one?" — and it's mostly driven by what each tool's API and file format make easy.
This isn't another "Notion is great, Obsidian is great, depends on you!" post. It's the developer cut: what you can actually build, what locks you in, and where each tool quietly fails when you push it.
The lock-in test, before anything else
Run this thought experiment for any note-taking tool: if the company shuts down tomorrow at midnight, what's your recovery story?
- Notion: You get a Markdown export. Databases collapse into flat folders, inline blocks lose fidelity, internal links break. Rebuilding a complex workspace elsewhere is a weekend job at best, "lost forever" at worst. The export technically works; the workflow that depended on it does not.
-
Obsidian: You already have a folder of
.mdfiles on your disk. Open it in VS Code, Logseq, Foam, or any markdown editor. You lose plugins; you don't lose data.
If portability matters to you (and as a developer, it should), Obsidian wins this round without firing a shot. Whether that's enough to outweigh everything else is the rest of this post.
Notion's API: programmable, well-documented, rate-limited
Notion's REST API is genuinely good. It's the rare SaaS API where the docs match the behaviour. Adding a page to a database is straightforward:
import { Client } from "@notionhq/client";
const notion = new Client({ auth: process.env.NOTION_TOKEN });
await notion.pages.create({
parent: { database_id: process.env.NOTION_DB_ID },
properties: {
Name: { title: [{ text: { content: "New idea" } }] },
Status: { select: { name: "Inbox" } },
Created: { date: { start: new Date().toISOString() } },
Tags: { multi_select: [{ name: "research" }, { name: "ai" }] },
},
});
This means you can build real automations: cron jobs that scrape an RSS feed into a Notion reading list, Slack bots that capture quotes, scripts that batch-import old notes. The API rate-limits at ~3 req/sec average per integration — fine for personal use, painful for bulk operations.
What you can't easily do via the API: full-text search across pages (limited), edit specific blocks deep inside a page (clunky), or react to page changes (webhooks exist but only for selected events). For "push data in" the API is great; for "pull data out and process" it's workable; for "react to edits" you're polling.
Obsidian's plugin API: TypeScript, local-first, no rate limits
Obsidian isn't a SaaS — it's a local app — so there's no REST API. Instead, you write plugins in TypeScript that run inside the app. Minimal plugin that adds a command:
import { Plugin, Notice } from "obsidian";
export default class StampPlugin extends Plugin {
async onload() {
this.addCommand({
id: "insert-timestamp",
name: "Insert ISO timestamp",
editorCallback: (editor) => {
editor.replaceSelection(new Date().toISOString());
},
});
this.addRibbonIcon("clock", "Stamp the page", () => {
new Notice(`Vault path: ${this.app.vault.adapter.getName()}`);
});
}
}
The plugin API exposes everything: read/write files in the vault, register commands, hook into edit events, build settings UIs, render custom views, traverse the link graph. The community has 1,500+ published plugins because the API is approachable.
The flip side: there's no way to interact with Obsidian from outside the app. If you want a cron job to add notes to your vault, you write directly to the markdown files on disk (or use a sync provider as the intermediary). That's not a bug — it's the philosophy. Obsidian doesn't own your data, so it doesn't need an API to give it back.
Where each one wins for developers
Notion wins on structured data. Databases with typed properties, filtered views, and rollups give you something close to a personal Airtable. If your "knowledge" includes things like a reading list with status/rating, a content calendar, a CRM-ish contact log, or a project tracker with kanban — Notion handles these in 5 minutes. Trying to recreate the same in Obsidian needs the Dataview plugin and custom query syntax.
Obsidian wins on text. Plain markdown means every other tool in your stack already speaks the format — VS Code, Git, GitHub, pandoc, your shell. Want to grep across 10,000 notes?
# Find every note that mentions "kubernetes" in your vault
rg -i "kubernetes" ~/vault --type md
# All notes modified in the last 7 days
find ~/vault -name "*.md" -mtime -7
# Word count across the entire vault
find ~/vault -name "*.md" -exec wc -w {} + | tail -1
You can't do any of this against Notion without using their API and burning rate-limit budget. For developers who already live in the terminal, this is genuinely transformative.
The split that actually works
After years of trying to pick one, here's what I run in 2026:
- Notion for structured projects. Content calendar, client tracker, weekly review, OKRs. Anything that benefits from "show me the kanban / show me the calendar / show me the filtered list of overdue items."
- Obsidian for thinking. Daily notes, research, code-related notes, journal, longform drafts, anything that grows by linking to other things.
- Resist the urge to sync them. I tried for a year. Every sync solution adds more failure modes than it solves. The two tools work better as separate brains for separate jobs.
The total cost is ~$50/year for Obsidian Sync (Notion Personal Free is plenty for my project tracking). Cheaper than any all-in-one solution that does both jobs worse.
A migration script that's actually useful
If you're considering moving from Notion → Obsidian, the export gives you a Markdown zip — but it's gnarly. Page IDs in filenames, broken internal links, embedded databases as inline tables. A small Python pass cleans most of it:
# notion-to-obsidian.py — quick cleanup pass on Notion's markdown export
import re
from pathlib import Path
EXPORT = Path("./notion-export")
OUT = Path("./obsidian-vault")
OUT.mkdir(exist_ok=True)
# Notion filenames: "Page Title abc123def456789012345678901234.md"
NOTION_ID = re.compile(r"\s+[a-f0-9]{32}(\.md)?$")
# Notion internal links: "[Title](Title%20abc123...md)"
LINK = re.compile(r"\[([^\]]+)\]\([^)]+%20[a-f0-9]{32}[^)]*\)")
for md in EXPORT.rglob("*.md"):
# Clean filename
clean_name = NOTION_ID.sub(".md", md.name)
# Read, rewrite internal links to wiki-style
text = md.read_text(encoding="utf-8")
text = LINK.sub(r"[[\1]]", text)
# Drop Notion's auto-generated frontmatter blocks if any
text = re.sub(r"^Created:.*\n", "", text, flags=re.MULTILINE)
text = re.sub(r"^Last Edited:.*\n", "", text, flags=re.MULTILINE)
(OUT / clean_name).write_text(text, encoding="utf-8")
print(f"Migrated {len(list(OUT.glob('*.md')))} files to {OUT}")
This is not a perfect migration — databases still become flat folders, image references need separate handling, callouts and toggles lose their special rendering. But it gets you to "openable in Obsidian without screaming" in one pass, which is the hard part.
Gotchas, both directions
Notion's API counts every call. If you're polling for changes every minute, that's 43k calls/month, well within personal limits but burns through integration quotas if you build on top. Use the last_edited_time filter to fetch only changed pages instead of full database queries.
Obsidian's plugin API can break across versions. Major Obsidian updates occasionally break plugins; if you depend on a plugin for core workflow, pin the plugin version and test before updating Obsidian.
Don't store secrets in Notion pages. Their search is full-text and accessible to anyone with workspace access — including past members whose invites you forgot to revoke. For API keys and secrets, use a real password manager, not your note app.
Obsidian Sync is end-to-end encrypted; Notion is not. Notion can read your data; Obsidian (with Sync) cannot. For sensitive personal journals, this matters. Self-host the markdown files via Git or Syncthing if you don't want a third party in the loop at all.
Both have AI features that send your notes to LLM providers. Notion AI sends to their backend (which calls OpenAI/Anthropic). Obsidian AI plugins use your API keys, so the API provider sees the data. Neither is "private by default" when AI is involved — read the docs before enabling.
TL;DR
- Notion has a great REST API. Easy to script "push data in" workflows. Locks your data in a database that exports poorly.
-
Obsidian has a great plugin API and gives you plain markdown files on disk. No external API, but you don't need one —
grep,find, and Git already work. - For developers specifically: Obsidian for thinking, Notion for tracking structured stuff. Use both, accept the split, stop trying to find one tool to rule them all.
If you write code for a living, the migration cost of getting trapped in someone's proprietary format is real. Bias toward plain text where the philosophy of your notes allows it.
Originally published on trackstack.tech with the broader non-developer comparison and FAQ.
Top comments (0)