Search Your Obsidian Vault From Outside Obsidian
This article is part 7 of my series on finding notes in Obsidian. The overview, with the map of all 12 parts, is The Complete Guide to Obsidian Search.
An Obsidian vault is a folder of Markdown files. That's the File over app principle Steph Ango wrote about, and it has a practical consequence for search: any tool that can read text files can search your notes. Most of them work with Obsidian closed, which the Obsidian CLI can't do.
Obsidian doesn't own your notes; it reads them. So the moment the app is too slow, too limited or simply not open, you can point something else at the same folder: a terminal tool, your operating system's search, a launcher, Git, a website or an AI agent. Nothing to export, nothing to sync, no API to ask permission from. Your notes are just files on disk, and decades of tooling were built to search files on disk.
When is it worth leaving the app? In six situations:
| Situation | Why Obsidian isn't the best tool | What to use |
|---|---|---|
| You need raw speed or a complex regular expression over the whole vault | Obsidian's Search slows down on big vaults, and its regex support stops at what the Search view understands | rg, ugrep, git grep |
| You're in a terminal, a script, a cron job or an AI agent | Obsidian is a GUI app; the CLI needs it running | rg, fd, fzf, yq, zk |
| You want to search your notes and everything else on your computer | Obsidian only sees its vault | Everything, Spotlight, Raycast, Alfred, Recoll |
| You're looking for something you deleted or changed months ago | Search only sees the current state of your notes | Git (git log -S, git show) |
| You want to send someone a link | A vault note isn't shareable; a published note is | Your published site, site: on Google |
| The note lives in another vault | Every Obsidian feature stops at the vault boundary | rg on several folders, qmd, MCP servers |
One warning before we start: these tools see text. They don't know that [[Zettelkasten]] and [[Zettelkasten|the slip-box]] point to the same note, they don't resolve aliases, and they don't understand properties the way Obsidian does. When you need the link graph, use Obsidian (or its CLI, from part 6). When you need raw text, speed or history, leave the app.
This part goes through each option: ripgrep, fzf and the rest of the terminal toolbox, your OS search and launchers, git history, your published notes, read-later and highlighting tools, pointer notes for the files that live outside your vault, and what to do with several vaults. A cheat sheet at the end collects the ripgrep and git commands.

TL;DR
- Your vault is a folder of Markdown files, so anything that reads text can search it, with Obsidian closed. Use Obsidian (or its CLI) for links, aliases and properties; leave the app for raw speed, regex and history.
- ripgrep finds an exact phrase in 0.15 seconds on my 30,000-note vault, where Obsidian's Search needs about 4. Pair it with fzf for a live full-text picker that opens the result in Obsidian.
- Bind a launcher or desktop search to a global hotkey: Everything or PowerToys Command Palette on Windows, Raycast or Alfred on macOS, Recoll or a rofi script on Linux.
- Git searches everything you deleted or changed.
git log -Stells you when a phrase appeared or disappeared, andgit show <sha>^:pathbrings a deleted note back. - Search your published notes when you want to share a link, and search Readwise or Zotero before your vault when the question is "where did I read X?".
- Make the vault the index of what lives elsewhere with pointer notes, and keep one vault: every vault boundary is a findability boundary.
The terminal: ripgrep, fzf and friends
ripgrep (rg) is the fastest way to search a vault from the terminal. It respects .gitignore, skips hidden folders (including .obsidian/), and runs in parallel. On my vault, it finds an exact phrase in about 0.15 seconds, where Obsidian's Search needs 4 to 8 seconds:
| Query | Obsidian Search (via the CLI) | rg -il --glob '*.md' |
|---|---|---|
zettelkasten | 0.4 s, 418 notes | 0.6 s (cold cache), 421 files |
"second brain" | 4.2 s, 297 notes | 0.15 s, 316 files |
obsidian | 2.6 s, 4,556 notes | 0.19 s, 4,396 files |
The counts differ slightly because Obsidian respects my excluded folders and matches file names too, while rg only reads content.
Install it with your package manager (brew install ripgrep, winget install BurntSushi.ripgrep.MSVC, sudo pacman -S ripgrep, sudo apt install ripgrep), then run it from your vault folder. -t md limits the search to Markdown files, which keeps PDFs, images and JSON out of your results.
Recipes that work on any vault:
# Files that mention a phrase (prints file names)
rg -il -t md "second brain" .
# Notes linking to [[Beta]] (plain, heading and alias forms)
rg -l -t md '\[\[Beta(\|[^\]]*|#[^\]]*)?\]\]' .
# Exact wikilink text, without escaping the brackets
rg -F -l '[[Project X]]' .
# Most-linked notes in the vault
rg -o --no-filename -t md '\[\[([^\]|#]+)' -r '$1' . | sort | uniq -c | sort -rn | head
# Open tasks
rg -n -t md '^\s*- \[ \]' .
# Notes with "status: draft" in their frontmatter
rg -l -U -t md '\A---\n(?s:.*?)^status:\s*draft\s*$(?s:.*?)^---' .
# Notes without frontmatter
rg -t md --files-without-match -U '\A---\n' .
# Two lines of context around each match
rg -n -C2 -t md "decision" .More ripgrep recipes for Markdown vaults
Here are the ones I reach for when the question gets more specific:
# Inline tags, ranked by frequency (requires a space or line start before #, so URL fragments don't count)
rg -o --no-filename -t md '(?:^|\s)#([A-Za-z][\w/-]*)' -r '$1' . | sort | uniq -c | sort -rn | head
# Notes whose frontmatter tags contain "ai" (list form or inline array form)
rg -l -U -t md '(?m)^tags:(?:\s*\[[^\]]*\bai\b|\s*\n(?:\s+- .*\n)*?\s+- ai\s*$)' .
# Unlinked mentions: "Zettelkasten" written as plain text, not inside [[ ]]
rg -n -t md -P '(?<!\[\[)\bZettelkasten\b(?![^\[\n]*\]\])' .
# Search note TITLES (file names), not content
rg --files -t md . | rg -i 'meeting'
# Notes that list an alias
rg -n -t md -A5 '^aliases:' . | rg -i 'pkm'
# Whole word only (finds "AI" and "ai", skips "said" and "maintain")
rg -lwi -t md 'ai' .
# Smart case: lowercase query = case-insensitive, any capital = case-sensitive
rg -S -l -t md 'Obsidian' .
# Exclude folders and file types with globs
rg -l -t md -i 'qmd' -g '!*.excalidraw.md' -g '!Templates/**' -g '!90 Archive/**' .
# Count matching lines per note, busiest notes first
rg -c -t md -i 'zettelkasten' . | sort -t: -k2 -rn | head
# Most recently modified matches first (slower: disables parallelism)
rg -l -t md -i 'pricing' --sortr modified .
# Machine-readable output for scripts (pipe into jq)
rg --json -t md 'qmd' . | jq -r 'select(.type=="match") | .data.path.text' | sort -uA few flags explain most of these:
-iignores case,-S(smart case) ignores it only when your query is all lowercase,-wmatches whole words, and-Ftreats the pattern as plain text so you don't have to escape[[,(or..-llists matching files,--files-without-matchlists the others,-ccounts matching lines per file (--count-matchescounts every match), and-C2,-A5,-B1add context lines.-g '!pattern'excludes paths.-gtakes globs relative to where you runrg, so-g '!Templates/**'skips theTemplatesfolder at the root of your vault; use-g '!**/Templates/**'to skip it at any depth.--hiddenand--no-ignoredo the opposite and bring.obsidian/and git-ignored files back (-uuis the shortcut for both).-U(multiline) lets a pattern span several lines, which is what you need for frontmatter.(?s:...)makes.match newlines inside the group only.-Pswitches to the PCRE2 engine, which supports lookarounds like(?<!\[\[)(the unlinked-mentions recipe needs it).-o -r '$1'prints only the captured group, which is how you extract tags or link targets into a list.
ripgrep gotchas (from real runs on my vault)
Two gotchas. First, when rg runs without a terminal attached (in a script, a cron job or an AI agent sandbox) and you don't pass a path, it waits for input on stdin and hangs. Always pass a path, even .. Second, rg doesn't know about aliases, resolved links or properties as Obsidian understands them. It sees text.
And a few more that bit me:
- Windows line endings break frontmatter regexes. The
\A---\nrecipes above assume Unix line endings. On my vault, 1,585 notes contain Windows line endings (\r\n). Counting public notes withrg -l -t md '^public_note:\s*true'returned 9,552 files; the frontmatter-only version with\A---\nreturned 9,267. It silently missed 281 notes that start with---\r\n. Add--crlfand\r?\nand you get 9,548:
``bash rg -l -U --crlf -t md '\A---\r?\n(?s:.*?)^public_note:\s*true\s*$(?s:.*?)^---' . ``
The naive line search still over-counts a little: it also matches notes that only mention public_note: true in their body, like the code examples in one of my process notes (which is itself private). That's the other reason to anchor frontmatter searches to the top of the file.
- Excalidraw drawings match everything. Excalidraw files are
.excalidraw.md, and their compressed drawing data is long strings of random-looking characters. Short queries match inside it. Exclude them with-g '!*.excalidraw.md', or use-w. - Shell aliases and agent hooks. Some shells alias
rgto something else, and some AI agent setups rewrite it on the fly. In scripts, callcommand rgor the full path (/usr/bin/rg) so you know what runs. - Quoting. Use single quotes around patterns, so your shell doesn't expand
$,!or backticks. On Windows PowerShell, single quotes work too, butcmd.exeneeds double quotes.
fzf: an interactive picker for your notes
fzf turns any list into a fuzzy picker: you type a few letters, it filters the list as you type, and you pick a line with the arrow keys. Combine it with fd (fast file finder) and bat (a cat with syntax highlighting, used for the preview) to pick a note by name:
fd -e md . ~/vault | fzf --preview 'bat --color=always --style=plain {}'That covers titles. For full-text search, the trick is to let fzf rerun rg on every keystroke instead of filtering a fixed list (that's the pattern from fzf's own "ripgrep launcher" documentation). Here's a shell function you can paste into your ~/.bashrc or ~/.zshrc. Type to search the content of every note; the preview shows the matching line in context; Enter opens the note in Obsidian:
# vs: live full-text search of an Obsidian vault, open the pick in Obsidian
# Needs: rg, fzf (0.38+), bat, jq. Usage: vs [vault folder]
vs() {
local vault="${1:-$HOME/vault}"
local RG="rg --column --line-number --no-heading --color=always --smart-case -t md -g '!*.excalidraw.md'"
local OPEN="xdg-open"; [ "$(uname)" = "Darwin" ] && OPEN="open"
( cd "$vault" || exit 1
fzf --ansi --disabled --prompt 'vault> ' \
--bind "change:reload:sleep 0.1; $RG {q} . || true" \
--delimiter : \
--preview 'bat --color=always --style=numbers --highlight-line {2} {1}' \
--preview-window 'right,60%,+{2}+3/3' \
--bind "enter:become($OPEN \"obsidian://open?path=\$(printf %s \"\$(realpath {1})\" | jq -sRr @uri)\")"
)
}How it works: --disabled turns off fzf's own filtering, change:reload reruns rg with your query ({q}), --delimiter : splits rg's path:line:column:text output so {1} is the file and {2} the line, and become replaces fzf with the command that opens the note. jq -sRr @uri URL-encodes the absolute path, spaces and slashes included, which is what the obsidian:// URI expects.
Gotchas: the sleep 0.1 avoids launching a search for every single keystroke when you type fast. On a 30,000-note vault, one or two letters return thousands of lines; type at least a full word before you expect something useful. And if you don't want to open Obsidian, replace the enter binding with --bind 'enter:become($EDITOR {1} +{2})' to jump straight to the line in your editor.
fd, ugrep, yq and the rest of the toolbox
- fd is a faster, friendlier
find. It respects.gitignoreand skips hidden folders, likerg. It's the best tool when you remember something about the file, not its content:
``bash fd -e md 'meeting' ~/vault # notes whose name contains "meeting" (-p: full path) fd -e md --changed-within 2d . ~/vault # notes modified in the last 2 days fd -e md -E Templates -E .trash . ~/vault # exclude folders fd -e md -0 . ~/vault | xargs -0 rg -l 'pricing' # combine with rg ``
- ugrep (
ug) is grep-compatible and adds boolean queries (ug -%% "obsidian sync -headless"), fuzzy matching, an interactive TUI (ug -Q) and PDF search. A few examples from its documentation:
``bash ug -r -%% --include='*.md' 'obsidian sync -headless' ~/vault # files with both terms, without the third ug -r -% --include='*.md' 'burnout|exhaustion' ~/vault # either term ug -r -Z2 --include='*.md' 'zettelkasten' ~/vault # fuzzy: up to 2 typos ug -Q -t markdown # interactive search pane ``
-% makes a query boolean per line, -%% per file (so the terms can be in different paragraphs). For PDFs stored in your vault, ug+ (or --filter="pdf:pdftotext % -") converts them to text on the fly. It's the closest thing to "Google search syntax" in a terminal.
- yq reads frontmatter:
yq --front-matter=extract '.tags' note.md. It only processes the frontmatter of the first file you pass, so loop over your notes:
``bash # Every note whose status is "draft" shopt -s globstar # bash only; zsh supports ** out of the box for f in **/*.md; do s=$(yq --front-matter=extract '.status // ""' "$f" 2>/dev/null) [ "$s" = draft ] && echo "$f" done ``
It's slower than rg, but it parses YAML for real: lists, quoted values and nested keys all work, and invalid frontmatter shows up as an error instead of a silent miss.
- mdq is "jq for Markdown":
mdq '# Tasks | - [ ]' note.mdprints the open tasks under a "Tasks" heading. It understands CommonMark, so wikilinks aren't first-class, but it's great for pulling sections out of long notes. - notesmd-cli (formerly the community "obsidian-cli", renamed after the official CLI shipped) searches note names and content without Obsidian running.
notesmd-cli searchopens a fuzzy finder on note names;notesmd-cli search-content "term"searches inside notes, with--no-interactiveand--format jsonfor scripts. Install it with Homebrew (yakitrak/yakitrak/notesmd-cli), Scoop or the AUR. - zk keeps its own index with link-aware queries (
--linked-by,--link-to,--orphan,--created-after). Runzk initin your vault (it creates a.zk/folder with a SQLite index), configure it to recognize wikilinks, and you get queries Obsidian's Search can't express in one line:
``bash zk list --link-to "Zettelkasten.md" # notes linking to a note zk list --linked-by "My MOC.md" --orphan # combine link filters zk list --tag "ai OR pkm" --created-after "last monday" zk list "pricing -draft" -i # full-text query, picked with fzf ``
- markdown-oxide and marksman are language servers: backlinks, references and "go to definition" for wikilinks in Neovim, VS Code, Zed or Helix. A language server is the thing that makes "find all references" work in a code editor; these two do it for notes. markdown-oxide was built for Obsidian-style vaults (it detects the
.obsidianfolder and understands headings, block references, tags and daily notes); install it withbrew,pacmanorwinget install markdown-oxide, then enable it in your editor's LSP settings. marksman is more general: go to definition, find references for[[wiki]]and[md]()links, and warnings for broken links. - jq isn't a search tool, but it post-processes the JSON that
rg --json,yq -o=json,obsidian ... format=jsonandqmd --jsonproduce.
And of course, grep works everywhere: grep -rni --include='*.md' 'zettelkasten' ~/vault. It's slower than rg and doesn't skip .obsidian/ on its own (add --exclude-dir=.obsidian), but it's installed on every Linux and macOS machine, which makes it the safe default in scripts you share.
Query your vault with SQL
If you think in SQL, look at these two:
- DuckDB has community extensions that read Markdown files and their frontmatter as tables:
read_markdown()(with sections and blocks), andread_yaml_frontmatter(), which turns every property into a column. That gives you queries like "every note withstatus = draft, grouped by folder", across 30,000 files, in one statement. - SQLite: zk and qmd already keep a SQLite index of your notes. You can also build your own full-text index (SQLite's FTS5) with
sqlite-utils, then browse it with Datasette.
For example, run duckdb from your vault folder:
INSTALL markdown FROM community; LOAD markdown;
SELECT parse_dirpath(filename) AS folder, count(*) AS drafts
FROM read_markdown('**/*.md', include_filepath := true)
WHERE metadata['status'] = 'draft'
GROUP BY folder ORDER BY drafts DESC;read_markdown() exposes frontmatter as a metadata map of strings (so compare with 'true', not true), and extract_extensions := 'obsidian' adds columns for wikilinks and tags. read_yaml_frontmatter() (from the yaml extension) gives you real typed columns, but on a big vault it can fail on a single inconsistency, like one note using Name and another name; add as_yaml_objects := true to get one frontmatter column instead.
For most people, Bases (part 5) or the Obsidian CLI's base:query will do the same job with less effort. SQL is for when you want to join your notes with other data.
Your OS search and launchers
Sometimes you want to search your notes without switching to Obsidian, or search your notes and everything else on your computer.
There are two families here. Desktop search engines (Everything, Windows Search, Spotlight, Recoll) index files across your whole computer: your vault is just one folder among many. Launchers (Raycast, Alfred, PowerToys Command Palette, Walker, rofi) are the keyboard-driven boxes you open with a hotkey; some have Obsidian-specific extensions that understand vaults, tags and headings. A launcher with an Obsidian extension is usually the better choice for notes. A desktop search engine is better when you don't remember whether the thing is a note, a PDF or an email.
Whatever you pick, bind it to a global hotkey. A search you can open from any app in under a second gets used. One that needs three clicks doesn't.
Windows
On Windows, Everything by voidtools finds files by name instantly, and it can search content with ext:md content:"exact phrase" (narrow it with a path, or it's slow). Windows Search can index Markdown content if you set .md to "Index Properties and File Contents" in Indexing Options. PowerToys Command Palette (the successor of PowerToys Run) uses the Windows index, and it has a community "Obsidian Notes" extension.
Everything reads the NTFS file table directly, which is why name searches are instant even across millions of files. Useful query syntax for a vault:
path:"D:\Vault" ext:md procrastfinds notes whose name contains "procrast" in that vault.path:"D:\Vault" ext:md content:"exact phrase"searches inside notes. Without a content index, Everything reads every file for this, so always narrow withext:and a path.dm:7daysfilters on modification date,regex:switches to regular expressions.
Everything also has a command-line client, ES (es.exe), which needs the Everything app running in the background:
es -path "D:\Vault" ext:md "meeting"
es -path "D:\Vault" -r "\d{4}-\d{2}-\d{2}\.md$" -sort date-modified-descending -n 20To open a result in Obsidian, use the obsidian://open?path= URI with the encoded absolute path (obsidian://open?path=D%3A%5CVault%5CNote.md). Obsidian figures out which vault contains the file.
Windows Search is built in, but it doesn't index the content of .md files reliably out of the box. To fix it:
- Open Indexing Options (search for it in the Start menu) and make sure your vault folder is in the indexed locations (Modify).
- Click Advanced → File Types, find
mdin the list (type it in the box at the bottom and click Add if it's missing). - Select Index Properties and File Contents. The filter column should say "Plain Text Filter".
- Rebuild the index (Advanced → Rebuild) and give it time.
Then content:zettelkasten ext:.md in File Explorer searches inside your notes.
PowerToys Command Palette replaced PowerToys Run in 2025. Open it with Win+Alt+Space. Its file search goes through the Windows index, so do the steps above first. For an Obsidian-aware experience, there's a community "Obsidian Notes" extension that searches your vault and previews notes in the palette (winget install zadjii.ObsidianNotesExtension). It's new, so test it before you rely on it.
Raycast also runs on Windows now, and its Obsidian extension works there too (see macOS below).
macOS
On macOS, Spotlight indexes your vault: mdfind -onlyin ~/Vault "zettelkasten" searches it from the terminal. Markdown content indexing has been flaky in some macOS versions, so check with mdimport if notes are missing. The Raycast Obsidian extension searches note titles, and content if you enable it, with tag filters. Its "exact match navigation" opens Obsidian at the matching line, which requires the Obsidian CLI to be enabled. With more than one vault, it asks you to pick a vault first. On Alfred, the Shimmering Obsidian workflow searches notes, aliases, headings and tags.
Spotlight from the terminal (mdfind) is underrated:
mdfind -onlyin ~/Vault "zettelkasten" # name + content
mdfind -onlyin ~/Vault 'kMDItemFSName == "*meeting*.md"c' # notes named "meeting"
mdimport -t -d2 ~/Vault/Some\ note.md # what Spotlight extracts from a file
mdls -name kMDItemContentType ~/Vault/Some\ note.md # how macOS classifies itIf Spotlight finds a note by name but not by content, check mdls: when macOS classifies .md as something other than text, it doesn't index the content. A bug that misidentified plain-text files existed from Mojave through macOS 26 and was fixed in macOS 27 (Howard Oakley tested it on plain text, not Markdown specifically). Also check System Settings → Spotlight → Search Privacy: if your vault folder (or the iCloud folder that holds it) is listed there, Spotlight skips it.
Raycast setup takes two minutes:
- Install the "Obsidian" extension from the Raycast Store.
- In its preferences, set your vault path (comma-separated for several vaults) and, optionally, folders to exclude. Folders you excluded in Obsidian's settings are excluded here too.
- Open the Search Note command's preferences and enable content search if you want to search inside notes, not just titles.
- Give Search Note a hotkey (Raycast Settings → Extensions).
Then: type to search, filter by tag with the dropdown (frontmatter and inline tags both count), and press Enter to open the note. Opt+C copies the note's content, Opt+V pastes it into the app you came from (handy to drop a note into an email). If nothing matches, you can create a note from your query. The extension has other commands worth a hotkey: Daily Note, Append to Daily Note, Quick Capture, Random Note, Bookmarked Notes and Search Media.
Alfred users have Shimmering Obsidian. It needs Alfred 5 with the Powerpack, plus two Obsidian plugins: Advanced URI and Metadata Extractor (the workflow reads Metadata Extractor's JSON export instead of parsing your vault on every search). Install the workflow, set your vault path, then use the o keyword: o pricing searches notes, aliases, folders and headings, o foobar #moc filters by tag, o obsidian h2 searches level-2 headings. It searches one vault at a time; the ov keyword switches vaults. If you'd rather not install plugins, an Alfred script filter around mdfind -onlyin <vault> does a simpler version of the same.
Linux
On Linux, Recoll is the best full-content desktop indexer (with a recollq CLI). KDE has Baloo, GNOME has LocalSearch. And any launcher that accepts a list (rofi, wofi, Walker's dmenu mode) works with fd -e md . ~/vault | rofi -dmenu -i.
- Recoll is a full-text desktop search engine (built on Xapian) with a GUI and a CLI. Add your vault to
topdirsin~/.recoll/recoll.conf, runrecollindex, then search withrecollq 'pricing AND decision'. It treats Markdown as plain text, so frontmatter and wikilinks are indexed as words, which is fine for search. - plocate (
plocate -i meeting) searches file names instantly from a database thatupdatedbrefreshes, usually daily. Good for titles, useless for content. - KDE: Baloo indexes files, and KRunner (
Alt+Space) shows the results. Enable content indexing in System Settings → File Search, or Baloo only sees file names. - GNOME: LocalSearch (formerly Tracker Miner, renamed in GNOME 47) feeds the Activities overview search. Whether it extracts the full text of
.mdfiles depends on the extractors installed on your system, so test it with a word that only appears in a note's body. - Ulauncher has an Obsidian extension with
on(open by file name),of(search content),od(daily note) andoc(quick capture) keywords. It hasn't been updated since 2023, but it's small and does what it says. - Walker is the default launcher on Omarchy. It has no Obsidian provider, but its dmenu mode accepts any list.
For rofi, wofi or Walker, this tiny script gives you a note picker that opens in Obsidian. Save it as ~/.local/bin/vault-pick, make it executable, and bind it to a hotkey in your window manager:
#!/usr/bin/env bash
# vault-pick: pick a note by name with rofi, open it in Obsidian
VAULT="$HOME/vault"
cd "$VAULT" || exit 1
note=$(fd -e md . | rofi -dmenu -i -p "note") # or: walker --dmenu / wofi --dmenu
[ -n "$note" ] || exit 0
xdg-open "obsidian://open?path=$(printf %s "$VAULT/$note" | jq -sRr @uri)"For content search, replace the fd line with rg -l -i -t md "$1" . and pass the query as an argument.
Mobile, and the glue for all of it
On mobile, you can run rg on Android in Termux (pkg install ripgrep fd fzf, then rg -t md term ~/storage/shared/Vault), and use the iOS Shortcuts and Android widgets I mentioned in part 6.
Whatever tool you use, obsidian://open?path=<absolute path> opens the result in Obsidian. Obsidian finds the vault that contains the file on its own. Encode spaces as %20.
That Obsidian URI is what turns any of these tools into an Obsidian launcher. Three forms are worth remembering:
obsidian://open?vault=<name>&file=<path from the vault root>opens a note when you know the vault (the.mdextension is optional).obsidian://open?path=<absolute path>opens a note when you only have its full path (most OS tools give you that).obsidian://search?vault=<name>&query=<query>brings up Obsidian's Search view with a query already typed, so a launcher can hand off to Obsidian's operators.
Git and GitHub: search your vault's history
My vault has been a Git repository since March 2024: 3,199 commits so far. Git is my backup, and it's also a search engine for everything I ever wrote, including what I deleted. I explain my setup in how I synchronize and back up my Obsidian notes.

Why bother? Because every other search tool in this series only sees the current state of your notes. You rewrote a paragraph three months ago and want the old version back. A note deleted during last year's cleanup turns out to matter after all. You want to know when you first wrote about a topic. Obsidian's Search can't answer any of that. Git can, usually in under a minute, as long as the change was committed.
Here's the mental model:
| Question | Command |
|---|---|
| Where does X appear now? | git grep |
| Where did X appear at an older revision? | git grep X <revision> |
| When was X added or removed? | git log -S X (the "pickaxe") or git log -G regex |
| Who changed this line, and when? | git blame, git log -L |
| What happened to this file (renamed, deleted)? | git log --follow, --diff-filter=D |
| Bring it back | git show <rev>:path, git restore --source=<rev> -- path |
And the commands I find most useful:
# When did a phrase first appear?
git log -S'qmd' --reverse --format='%h %ad %s' --date=short -- '*.md' | head -1
# Every commit whose changed lines match a regex
git log -G'status/(draft|done)' --oneline -- '*.md'
# Every deleted note
git log --diff-filter=D --name-only --format='%h %ad' --date=short -- '*.md'
# Recover a deleted note: take the parent of the commit that deleted it
git show <sha>^:"path/to/Deleted note.md" > recovered.md
# The full history of one note, across renames
git log --follow -p -- "path/to/My note.md"
# Notes you touched in the last two weeks
git log --since='2 weeks ago' --name-only --format= -- '*.md' | sort -u
# A note as it was on a date
git show $(git rev-list -1 --before=2026-09-01 HEAD):"path/to/My note.md"
# Prose-friendly diffs
git diff --word-diff -- "path/to/My note.md"-S finds commits that change the number of occurrences of a string, so it misses a line that only moved. -G matches any changed line. On my vault, a pickaxe search over the whole history takes about 16 seconds. Don't run git grep over every revision ($(git rev-list --all)): on just 200 revisions it took 30 seconds and printed the same files thousands of times.
Recover a deleted note, step by step
You know (roughly) the note's name, and it's gone:
- Find the commit that deleted it.
git log --diff-filter=D --format='%h %ad' --date=short -1 -- '**/Lost note.md'prints the short hash and the date. Don't remember the exact name? Drop the path filter, list every deleted note with the command above, and pipe it throughrg -i 'lost'. - Look at it before restoring.
git show <sha>^:"path/to/Lost note.md"prints the note as it was in the parent of the deleting commit (that's what^means: the commit just before). In the deleting commit itself the file no longer exists, which is whygit show <sha>:pathfails. - Restore it.
git restore --source=<sha>^ -- "path/to/Lost note.md"puts it back in your vault, at its old path. Obsidian picks it up immediately. Commit it, and you're done.
Don't remember the name at all, only something it said? Search the content of the deletions with the pickaxe: git log -S'a phrase you remember' --diff-filter=D --name-only --format='%h %ad' --date=short -- '*.md'.
More history recipes
# Current content: fast, only tracked files, with folder exclusions (pathspecs)
git grep -n -i -w 'qmd' -- '*.md' ':!*.excalidraw.md' ':!90 Archive'
# Files containing both terms (on any line), names only
git grep -l --all-match -e 'obsidian' -e 'pricing' -- '*.md'
# Search the vault as it was on a date
git grep -n 'pricing' $(git rev-list -1 --before=2025-06-01 HEAD) -- '*.md'
# When was a note created?
git log --diff-filter=A --follow --format='%h %ad' --date=short -- "path/to/My note.md"
# Renamed notes (old name -> new name)
git log --diff-filter=R -M --name-status --format='%h %ad' --date=short -- '*.md'
# Every change to one property in one note
git log -G'^rating:' -p -- "path/to/My note.md"
# The history of one section, by heading (needs the .gitattributes line below)
git log -L ':Tips:path/to/My note.md'
# Who (or which device) last touched each line
git blame -w -C --date=short -- "path/to/My note.md"
# Commits you "lost" after a reset or a bad rebase
git reflog --date=isoHere's what the section-history command printed on my qmd note, for its "Tips" section. One command, and I can see exactly when I added the tip about excluding noise directories:
$ git log -L ':Tips:30 Areas/33 Permanent notes/33.02 Content/qmd.md' -n1 --format='%h %ad' --date=short
358ad63528 2026-05-20
@@ -127,3 +127,15 @@ ### Basic workflow
## Tips
- Create embeddings using the CPU: `alias qmd='NODE_LLAMA_CPP_GPU=false qmd embed'`
+- Exclude noise directories from a collection with an `ignore` list in `~/.config/qmd/index.yml`. ...And --word-diff shows prose changes the way a human reads them, word by word instead of whole lines (excerpt from the latest change to the same note):
updated: [-2026-05-26T11:44-]{+2026-06-17T16:44+}
{+- [[Semantic Search]]+}
{+- [[Embeddings]]+}A few settings help with a Markdown vault:
echo '*.md diff=markdown' >> .gitattributes # headings become hunk headers in diffs
git config core.quotePath false # show "Café.md" instead of escaped bytes
git config diff.renameLimit 20000 # rename detection in big vaultsWhat each one does:
diff=markdowntells Git to use its built-in Markdown driver, so headings play the role functions play in code. Diffs then show the enclosing## Headingabove each change,git grep -pshows which section a match is in, andgit log -L ':Heading:file.md'follows one section through time (without it, that command fails with "no match").core.quotePath falsestops Git from escaping accented characters. Without it,Café.mdshows up as"Caf\303\251.md", which breaks copy-paste into the next command.diff.renameLimit: Git detects renames by comparing files, and gives up past 1,000 files by default. On my vault it printed "exhaustive rename detection was skipped due to too many files" and asked for at least 11,856. Without enough room,--followand--diff-filter=Rmiss renames.
Also consider writing one sentence per line in long notes ("semantic line breaks"). Markdown renders it as a normal paragraph, and line-based diffs and blame become much more precise. If that's too unusual for you, --word-diff gets you most of the way.
Real-run gotchas
HEAD@{2026-09-01}is a trap. It looks like "the vault on September 1st", but it reads your local reflog, which expires (90 days by default) and doesn't exist on a fresh clone. Usegit rev-list -1 --before=2026-09-01 HEADinstead, as in the recipes above.- Git only knows what you committed. If your auto-commit runs every 10 minutes, anything you wrote and deleted between two commits is gone from Git. File Recovery or Obsidian Sync's version history (part 6) cover that gap.
git whatchangedis gone. Old tutorials use it. Git 2.55 refuses to run it; usegit log --raw --no-merges.- Short patterns match noise. An unanchored
qmdmatched compressed data inside Excalidraw files. Use-wand':!*.excalidraw.md'. - Big histories are slow. My pack is 3.5 GiB for 30,309 tracked notes. Scope your searches with
-- '*.md'or a folder, and add--no-renameswhen you don't need rename detection.
One tip if you use the Obsidian Git plugin: its default commit message ("vault backup" plus a date) makes git log --grep useless. Content search with -S and -G still works, and that's what matters. The plugin also has a history view and "line authoring" (git blame in the margin).
The plugin's commit message template supports placeholders like {{numFiles}} and {{files}}, which make --grep a bit more useful. Its history view (command "Open history view") lists commits with their changed files; click a file to see its diff. Line authoring ("Git: Toggle line author information") shows the date of each line's last change in the gutter, with an age heat map (recent lines in red, older ones in blue). It works in Live Preview and Source mode, desktop only. Neither feature searches content across history: for that, use the commands above.
If you'd rather not touch the terminal at all, my Time Machine plugin brings that history into Obsidian. It puts the note's git commits and its File Recovery snapshots on one timeline, with diffs and selective restore, so it's the GUI alternative to git log -p and git show for a single note. I cover it in "Recover old versions and deleted notes" in part 6.
Terminal UIs sit in between. tig (tig -- "path/to/My note.md") browses a note's history, and tig grep pattern opens a grep view. LazyGit lets you search the commit list with /, filter it by path, and press c in a commit's file list to restore that file from the selected commit. forgit wraps Git in fzf pickers: glo (log with preview), gbl (blame), gcff (check out a file from an older commit). In VS Code, GitLens adds file history and a commit search by changes (pickaxe-style); some of its graph search features need a paid plan for private hosted repositories. And gitk has a "Find" box with "adding/removing string" (that's -S) and "changing lines matching" (that's -G) modes.
A DIY version with fzf, for when you want to browse every commit that touched a phrase:
git log --oneline -S"pricing" -- '*.md' | fzf --preview 'git show --color=always {1} -- "*.md"'GitHub, GitLab and other hosts
GitHub and GitLab can search your repository too, with limits. GitHub code search only indexes the default branch, skips files over 350 KiB, returns at most 100 results and has no history search (commit search only looks at messages). gh search code 'zettelkasten' --repo me/vault --extension md works from the terminal. GitLab's exact code search and advanced search need a paid tier.
On GitHub's website, the code search syntax is richer than the CLI's:
repo:me/vault path:*.md "status/archived"for an exact phrase in Markdown files.repo:me/vault language:markdown pricing NOT path:"90 Archive/"to exclude a folder (quotes, because of the space).repo:me/vault /\[\[qmd\]\]/for a regex (here, wikilinks toqmd).
Be aware of what you lose: gh search code uses GitHub's older search API, so no regex, and results can differ from the website. You must be signed in, lines are truncated at 1,024 characters, and very large repositories may not be indexed at all (mine is 3.6 GB on GitHub and is still indexed). For history, GitHub's web UI has a History button on every file (it still works for deleted paths if you type the URL) and a Blame view with "View blame prior to this change". gh search commits pricing --repo me/vault searches commit messages only.
GitLab has three search levels: basic search (all tiers, exact substring, with filename:, path: and extension: filters), advanced search (Elasticsearch, paid tiers, with "phrase", -exclude and ~fuzzy) and exact code search (Zoekt, paid tiers, with a regex mode). All of them search the default branch.
Gitea and Forgejo are good fits if you self-host your vault's remote. Without configuration, their code search falls back to git grep. Enable the repository indexer (REPO_INDEXER_ENABLED = true) and limit it to **.md for proper indexed search. Sourcegraph can search inside historical diffs (type:diff), which is a hosted pickaxe, but only on a self-hosted instance or for public repositories.
[!warning] Privacy A private repository is still stored unencrypted on the host's servers. And history is forever: deleting a note doesn't remove it from past commits, clones or the remote. Purging it requires rewriting history (git filter-repo) and a force-push. Keep private folders out with.gitignore, or encrypt them with git-crypt. Treat any secret you committed as leaked.
There's a trade-off with encryption: the host can't search what it can't read. With git-crypt, your local git grep and git log -S still work on your decrypted clone, but GitHub's code search sees encrypted noise. If your vault is public, assume it's indexed by GitHub search, code search engines, archives and AI crawlers, forks included. And remember that Git doesn't need a host at all: a bare repository on a NAS or a USB drive gives you every command in this section with nobody else holding a copy.
Search to share: your published notes
I publish about 9,500 of my notes on https://notes.dsebastien.net with Obsidian Publish. A note is published when its public_note property is true. Dataview Serializer writes the query results into those notes, so the lists and Maps of Content render on the published site too.
That public Digital garden is also a finding tool. When someone asks me about a topic I've already written about, I search my published notes rather than my vault, because every hit there is a link I can share right away. Two ways to do it:
- the search box on the site itself
- Google:
site:notes.dsebastien.net "zettelkasten", orsite:notes.dsebastien.net intitle:procrastination
Then I send the link instead of re-explaining. I call it "search to share".
Why not search the vault and then look for the published version? Because half the hits in my vault are private: tasks, meeting notes, journal entries, drafts. Searching the public site filters all of that out for free. Every result is, by definition, something I'm happy to share, with a stable URL, the right formatting, and the links to related notes already working. A reply that says "I wrote about this, here" and links to a note also gives the other person somewhere to keep reading.
It works the other way around too: a note on a public site can be found by anyone, so a question you answer once in a published note stops being a question you answer again and again.
Keep in mind that Publish doesn't render Dataview queries, embedded query blocks or Bases. That's one more reason to serialize the queries in your published notes. And the site: search depends on Google's crawl, so recent notes may not show up yet.
My Dataview Serializer plugin does that serialization: it runs the query and writes the results as plain Markdown links below it, so Publish (and Google, and AI agents) see a real list instead of a code block.
A few tips to make "search to share" work well:
- Use Google operators.
site:limits results to your domain, quotes force an exact phrase,intitle:searches page titles only, and-wordexcludes a term.site:notes.dsebastien.net intitle:procrastination -newsletteris a perfectly good query. - Make it a launcher shortcut. A Raycast Quicklink with an argument turns "search my published notes" into a hotkey. Create a Quicklink with this URL:
https://www.google.com/search?q=site:notes.dsebastien.net+{argument name="query"}. Raycast prompts for the query and URL-encodes it for you. Most browsers can do the same with a custom search engine keyword. - Help Google find your notes. Publish generates a sitemap at
/sitemap.xml. Submit it in Google Search Console, use a custom domain (Obsidian staff have said that sites underpublish.obsidian.mdonly get crawled when Google crawls the whole domain), and add adescriptionproperty to important notes so search results show something meaningful. Owners of large Publish sites report indexing gaps, so the site's own search box remains the reliable option. - Keep URLs stable. Renaming a published note changes its URL, which breaks every link you ever shared. Publish's
permalinkproperty gives a note a URL that survives renames.
If you publish with something else: Quartz has a built-in full-text search (Ctrl/Cmd+K, titles ranked above content, # for tags), and Pagefind adds static search to any generated site.
Quartz's search runs entirely in the browser (it uses FlexSearch), shows the top 5 results with a short excerpt, and needs the ContentIndex emitter enabled. Ctrl/Cmd+Shift+K jumps straight to tag search. Pagefind works with the output of any static site generator (Hugo, Astro, Eleventy, Jekyll, Quartz): run npx -y pagefind --site public after your build and it creates a search index split into small chunks, so even a 10,000-page site stays fast (its documentation cites under 300 kB of total download for a search on a site that size). Astro's Starlight theme ships with it by default.
Search before the vault: read-later and highlights
Not everything you read belongs in your vault. A lot of it lives in your read-later and highlighting tools, and they have their own search:
- Readwise and Reader: Readwise has an official MCP server, so AI assistants can search your highlights (its search combines full-text and semantic matching). When the question is "where did I read X?", search Readwise first. And only import into your vault what you actually process: importing every highlight bloats your search results.
- Zotero: its quick search has an "Everything" mode that includes the full text of indexed PDFs.
- Raindrop.io: full-text search of saved pages on the paid plan.
- Your browser history: Chrome has an opt-in AI-powered history search, for things you saw but didn't save.
Think of these as the layer before your vault. Your vault holds what you processed; these tools hold what you merely read, saved or highlighted. That's a much bigger pile, and searching it is a different job.
Readwise and Reader
Readwise's web app searches all your highlights, and Reader searches the documents you saved (full text included). The more interesting part is the Readwise MCP Server: plug it into Claude, ChatGPT or any agent that speaks the Model Context Protocol (MCP), and you can ask "what did I highlight about spaced repetition?" in plain language. The official server runs remotely at https://mcp2.readwise.io/mcp; clients that only support local servers can use the wrapper npx -y mcp-remote https://mcp2.readwise.io/mcp. It exposes both sides: highlight search for Readwise, document search, tags and locations for Reader. You need a paid Readwise account.
In my setup, the Readwise MCP server is configured right next to the vault's own search tools, so my AI assistant can search my highlights and my notes in the same conversation. The Readwise official plugin for Obsidian brings highlights into the vault, and that's exactly where the "import only what you process" rule matters.
Zotero
Zotero's quick search (top of the main window) has three modes, and the default one doesn't search inside your PDFs:
- Title, Creator, Year: the default, fast, metadata only.
- All Fields & Tags: adds abstracts, tags and your notes (and annotations, in recent versions).
- Everything: adds the full text of indexed PDFs, EPUBs and web snapshots.
Switch to "Everything" when you're looking for a sentence you read rather than a paper you remember. Zotero only indexes the first 100 pages (or 500,000 characters) of each file by default; raise the limits in Settings → Search if your PDFs are long. For AI access, the community zotero-mcp server lets an agent search your library the same way the Readwise one does.
Raindrop.io and your browser
Raindrop.io keeps permanent copies of your bookmarks on the Pro plan and searches their full text (pages, PDFs and EPUBs, but no OCR on images). Its 2026 updates added an AI assistant, brought semantic search back for paid plans, and opened an MCP server on the free plan. If you use the Raindrop Highlights plugin for Obsidian, the same rule applies as with Readwise: import what you process, not everything.
Chrome's AI history search is opt-in (Settings → Experimental AI), and you use it by typing @history in the address bar followed by a description ("@history that article about note-taking with a blue header"). It only covers pages you visit after enabling it, and reports say your history is processed by Google. It's for the "I saw it last week but didn't save it" moments.
Find what lives outside your vault
Everything above is about searching your vault from elsewhere. This is the reverse problem: finding, from your vault, the things that live somewhere else. Obsidian's Search, the quick switcher, Bases and the graph only see files inside the vault. A PDF in Google Drive, a spreadsheet on a network share or a video on an external disk doesn't exist for them. And in the other direction, your task manager, your calendar and your email have no idea your notes exist.
You can't (and shouldn't) move everything into the vault. Large media bloats sync, shared folders belong to a team, and some files have to stay where other people or tools expect them. Following the single source of truth principle from part 3 ("One place to look first"), make the vault the index instead. Three tools do the job: pointer notes, links to local files, and links into your vault that you paste elsewhere.
Pointer notes: a findable stand-in for any file
A pointer note is a small note that describes something outside your vault and links to it. It gets a good name, a type, properties and links like any other note, so every finding tool in this series works on it, even though Obsidian can't see the file itself.
---
tags:
- type/document
created: 2026-03-14
counterparty: ACME
expires: 2027-03-31
---
# Contract - ACME - 2026
Service contract with ACME, signed on 2026-03-14.
Renewal notice due three months before it expires.
- File: [Contract - ACME - 2026.pdf](<file:///D:/Google Drive/Contracts/Contract - ACME - 2026.pdf>)Now acme contract in the quick switcher finds it, [counterparty:ACME] in Search finds it, a Base can list every document that expires this year, and rg and AI agents see it because it's plain Markdown. Two minutes of writing, and you never dig through Drive folders for it again.
Write the description with the words you'll search for later. The file name of a scan is often useless (Scan_0042.pdf); the pointer note is where the real name lives. Attachments inside your vault deserve the same treatment (see "Name attachments so you can find them" in part 9).
Link to local files with file:///
Obsidian has no special syntax for files outside the vault, but a regular Markdown link to a file:/// URL works: click it, and the file opens in its default application. If the path contains spaces, wrap it in angle brackets or replace each space with %20:
[Contract](<file:///D:/Google Drive/Contracts/Contract - ACME - 2026.pdf>)
[Budget](<file:///Users/you/Dropbox/Finance/Budget 2026.xlsx>)
[Project share](<file:///\\nas\projects\ACME>)The last one points to a folder on a Windows network share.
Typing paths by hand gets old fast. Better File Link adds an "Add file link" command that opens a file picker and writes the link for you. It can link to the containing folder instead of the file, and it has a "Check for broken file links" command. That last one matters, because Obsidian doesn't track these links at all (see the gotchas below).
Keep file links working on every device
A file:/// link stores an absolute path, and absolute paths differ per machine. The same Dropbox folder can be D:\Dropbox on your desktop and /Users/you/Dropbox on your laptop. Two plugins replace the absolute path with a name you define once per device:
- External Namespaces (desktop only) registers prefixes like
dropbox, each with its own local folder on each device. Paste a Windows path from that folder, and the plugin turns it into a link like[smith2020.pdf](obsidian://ens?p=dropbox:papers/smith2020.pdf). On another computer, you only tell it wheredropboxlives there. - External File Linker embeds outside files with
![[external:path]], and uses "groups" for folders that live at different paths on different devices:![[group:Dropbox/Contracts/Contract - ACME - 2026.pdf]]. It works on Windows, Linux, macOS, Android and iOS.
Both are small plugins, so run them through the checks in part 9 before you depend on them.
What about symbolic links, to make an outside folder appear inside the vault so Search can see it? Obsidian's documentation is blunt: "We strongly advise against using symbolic links. By using symbolic links and junctions in your vault, you risk losing or corrupting your data, or crashing Obsidian." It also warns that they may not play well with any kind of sync. Pointer notes are boring, and they never corrupt anything.
Link into your vault from other apps
The other direction is just as useful. Every note has an Obsidian URI, and Obsidian gives it to you in three places:
- the command palette: Copy Obsidian URL for current file
- the note's More options menu: Copy path → as Obsidian URL
- on desktop, right-click a file in the file explorer: Copy path → as Obsidian URL
You get an obsidian://open?vault=...&file=... link. Paste it in a task in your task manager, the description of a calendar event, an email draft, a ticket or a spreadsheet cell. When the time comes, one click takes you to the exact note, instead of searching for it in a hurry. I keep reference notes on Obsidian URL Deeplinks and how to create them. The other URI forms, for scripts and launchers, are earlier in this article, in "Mobile, and the glue for all of it".
Web pages
For web resources, you already have the read-later and highlighting tools above, and the core Bookmarks plugin (part 8) can bookmark pages you open in the Web viewer. On iOS and iPadOS 18 or later, Obsidian's Share Sheet (Obsidian 1.13 or later) has a New bookmark location, and Shortcuts has a Bookmark Link action, so saving a URL from any app takes two taps.
Keep in mind that a bookmark is findable by its title, in the Bookmarks pane. If you'll look for a page by topic, clip it or write a pointer note: then it has tags, properties and links, and Search sees it.
Gotchas
- Obsidian doesn't track links to outside files. Move or rename the file, and the link breaks silently: no backlinks, no unresolved link, no automatic update. The description in a pointer note tells you what to look for, and Better File Link's check finds the broken ones.
- Copied Obsidian URLs break too. They contain the vault name and the note's path. Obsidian updates internal links when you rename or move a note, but it can't touch a URL you pasted into another app. From other apps, link to notes whose names and locations are stable: project notes, hubs, Maps of Content.
file:///links are desktop links. On your phone, a path likeD:/Google Drive/...points nowhere. If you need the file on mobile, add your cloud drive's share link to the pointer note as well.- Search sees the note, never the file. Neither Obsidian, nor
rg, nor your AI assistant reads the PDF behind a pointer note. Put the facts you'll search for (dates, amounts, names) in the note itself, or transcribe the document (part 9).
When the source is gone: link rot
Finding the note is only half the job if the note's value is a URL. Web pages move, get paywalled or vanish. That's Link rot, one of the Information diseases every long-lived knowledge base catches sooner or later. You search, you find your note about that great article, you click, and you get a 404.
Three habits protect you:
- Save the text, not only the link. The Obsidian Web Clipper converts the page to Markdown and saves it in your vault, along with its metadata. The content is then searchable with every tool in this series, and it survives the original page. For the sources you'll cite or build on, that's the safest option. For the rest, a short summary in your own words already keeps the idea alive.
- Keep an archived copy of the URL. The Wayback Machine (web.archive.org) stores snapshots of public pages. The Wayback Archiver plugin automates it: it scans the current note, a selection or the whole vault for links, saves a snapshot of each through the Wayback Machine's API, and appends an "(Archived on …)" link next to the original (or replaces it, if you prefer). It needs API keys from your archive.org account, and it keeps a log of failed attempts that you can retry. The older Link Archive plugin hasn't had a release since 2021.
- Know which links matter. The External Links plugin lists the external links of the current note in the side panel and shows which other notes point to the same URL. From the terminal, this lists the URLs you cite most often across your vault:
rg -o --no-filename -g '*.md' 'https?://[^\s)>\]"]+' . | sort | uniq -c | sort -rn | head -20A URL you cite in 15 notes deserves an archived copy (or a note of its own) much more than one you clipped once.
Gotcha: archiving sends your URLs to a third party, and public archives only store public pages. Filter out private links (shared documents, internal tools, anything with a token in the URL) before you run an archiver on the whole vault.
Several vaults
Obsidian has no built-in cross-vault search. Search, the quick switcher, backlinks, the graph and Bases all stop at the vault's boundary. Every vault boundary is a findability boundary.
Steph Ango's advice in his "How I use Obsidian" post is clear: "Avoid splitting content into multiple vaults." I agree. If you want separation, do it inside one vault: folders by type, Excluded files for noise, workspaces for context, path: in your searches.
He makes one exception himself: a separate vault for his website. Obsidian's own documentation is neutral (one vault or several, your choice), but it warns against vaults nested inside other vaults, because links are local to a vault and may not update correctly. And people who split usually do it for separate plugin sets, separate windows, or privacy. All three have answers inside a single vault:
- Noise: Settings → Files and links → Excluded files hides folders from Search, the graph and unlinked mentions.
- Context: workspaces (core plugin) save and restore a layout per context, like "Work" or "Writing".
- Scope:
path:"20 Work"in a search, saved as a bookmark, gives you a "work only" search in one click. - Privacy: separate vaults don't protect much if they sit side by side on the same disk. If a folder must not sync or be published, exclude it from Sync, from Git (
.gitignore) and from Publish.
If you really need several vaults (a client vault, a shared vault, a website vault), bridge them outside the app:
rg -i "term" ~/VaultA ~/VaultBsearches several vaults in one pass- qmd can index each vault as a separate collection and search across all of them
- some MCP servers (like obsidian-mcp) can serve up to ten vaults to an AI agent
- the Obsidian CLI works one vault at a time:
obsidian vault="Work" search query="…"(loop overobsidian vaultsto cover them all) - the Multi-Vault Navigator plugin searches across vaults from inside Obsidian, but it's new, desktop only and has a tiny user base
ripgrep takes as many folders as you like, and prints the full path of each match, so you can see which vault it came from. Combine it with the vs fzf function from the terminal section above, and obsidian://open?path= opens the pick in the right vault automatically:
rg -il -t md "pricing" ~/vaults/Personal ~/vaults/Work ~/vaults/Client-AcmeThe Obsidian CLI has no "all vaults" flag, but obsidian vaults lists the vaults Obsidian knows about, one per line, so a loop covers them. vault= must be the first parameter:
obsidian vaults | while read -r v; do
echo "== $v"
obsidian vault="$v" search:context query="pricing" limit=5
doneIt uses Obsidian's own index, so operators like tag: and path: work, but Obsidian has to be running.
qmd is the strongest option if you also want search by meaning. Add one collection per vault, embed once, and every query searches all of them unless you scope it:
qmd collection add ~/vaults/Personal --name personal --mask "**/*.md"
qmd collection add ~/vaults/Work --name work --mask "**/*.md"
qmd embed
qmd query "how we decided on pricing" # all vaults, hybrid search
qmd search "invoice" -c work # one vault, keyword searchIts MCP server then gives an AI agent one search over every vault. I cover qmd (and how to keep its index fresh) in part 11.
MCP servers that read files directly can hold several vaults too. obsidian-mcp (by Steven Stavrakis) accepts up to ten vaults, one --vault id=/path argument each, and doesn't need Obsidian running; the agent searches each vault by id and combines the results. Servers built on the Local REST API plugin, by contrast, talk to one running vault each.
Multi-Vault Navigator is the only plugin I found that searches across vaults from inside Obsidian: fuzzy search over all your vaults (it reads Obsidian's vault list), read-only previews of notes from other vaults, cross-vault backlinks and a "Copy to current vault" action. It's desktop only, and Obsidian's staff haven't reviewed it manually yet. Promising, but test it on a copy first.
And watch out for launchers that look multi-vault: the Raycast extension accepts several vault paths, but Search Note asks you to pick one vault first, then searches only that one.
Cheat sheet
ripgrep
rg -il -t md "phrase" . # files containing a phrase
rg -F -l '[[Note Name]]' . # notes linking to a note
rg -n -t md '^\s*- \[ \]' . # open tasks
rg -n -C2 -t md "term" . # with contextMore:
rg -l -t md '\[\[Beta(\|[^\]]*|#[^\]]*)?\]\]' . # links to [[Beta]], all forms
rg -o --no-filename -t md '\[\[([^\]|#]+)' -r '$1' . | sort | uniq -c | sort -rn | head # most-linked notes
rg -l -U -t md '\A---\n(?s:.*?)^status:\s*draft\s*$(?s:.*?)^---' . # status: draft in frontmatter
rg -t md --files-without-match -U '\A---\n' . # notes without frontmatter
rg -i "term" ~/VaultA ~/VaultB # several vaults at onceAlways pass a path (even .) in scripts and agents, or rg waits for input and hangs.
git
git log -S'phrase' --oneline -- '*.md' # when it appeared or disappeared
git log --diff-filter=D --name-only -- '*.md' # deleted notes
git show <sha>^:"path/to/note.md" # a deleted note's content
git log --since='2 weeks ago' --name-only --format= -- '*.md' | sort -uMore:
git log -G'status/(draft|done)' --oneline -- '*.md' # commits whose changed lines match a regex
git log --follow -p -- "path/to/My note.md" # a note's full history, across renames
git show $(git rev-list -1 --before=2026-09-01 HEAD):"path/to/My note.md" # a note as it was on a date
git diff --word-diff -- "path/to/My note.md" # prose-friendly diffFAQ
Can I search across several vaults? Not inside Obsidian (except with the young Multi-Vault Navigator plugin). Outside, rg and qmd can search several vault folders at once. Better: keep one vault.
Conclusion
Obsidian is the right place to search when you need links, aliases and properties. For everything else (raw speed, complex regex, history, files outside the vault, other vaults), your notes are plain files, and the terminal, your OS, git and the web can search them without asking Obsidian. Pick one tool per job, give it a hotkey, and commit often, so git has something to search.
Next in the series: Navigate Your Obsidian Vault - Links, Graphs, Bookmarks and Hubs. Previous: Obsidian Search Beyond the Basics - Version History, CLI, Mobile and Performance.
Prefer to read the whole series in one place? I turned it into an ebook, The Obsidian Search Handbook, with an exercise at the end of every chapter (the Complete edition adds a starter pack and worksheets).
Free cheat sheet. The commands and operators worth remembering, and the search escalation ladder (which tool to try first, depending on what you remember about the note), on 13 pages you can keep next to your vault. Enter your email and I'll send it right away: the Obsidian Search Cheat Sheet.

Get the free Obsidian Search Cheat Sheet. 13 pages to keep next to your vault: the search operators worth remembering and the search escalation ladder. Enter your email and I'll send it right away. You'll also get a few short follow-up emails about finding notes in Obsidian, and you can unsubscribe at any time.
About Sébastien
Ready to get to the next level?
Found this valuable? Share it with someone who needs it.

