vulpea · vulpea-ui · vulpea-journal · vulpea-para
A database layer for your org-mode notes. Vulpea indexes your notes and provides fast queries for tags, links, metadata, and full-text search - all without blocking your workflow.
Org-mode is powerful, but working with hundreds or thousands of notes becomes difficult. Finding notes, discovering connections, and querying your knowledge base requires tooling beyond what org-mode provides.
Vulpea solves this by maintaining a database of your notes that stays in sync with your files. You get:
- Fast note finding - Search by title, tags, or content across thousands of notes
- Connection discovery - Find what links to what, explore backlinks
- Rich queries - Filter notes by tags, metadata, links, or custom predicates
- Non-blocking sync - Database updates happen in the background, never interrupts your typing
- External change detection - Works with git, Dropbox, Syncthing - files changed outside Emacs are detected automatically
Personal knowledge management - Use M-x vulpea-find to navigate your notes, M-x vulpea-insert to create links between ideas. Vulpea handles Zettelkasten-style workflows where connections matter.
Building applications - Vulpea provides a foundation for note-based apps. Vino uses Vulpea to manage wine collections with ratings, producers, and regions. The included journal module provides daily notes with widgets.
Large collections - Designed to scale. The async architecture and optimized queries handle 100k+ notes without degrading performance.
Vulpea is designed as a foundation, not an application. Where tools like org-roam aim to replicate Roam Research in Emacs (and do it very well), Vulpea provides a stable API layer for building your own note-based workflows and applications.
Key differences:
- Schema as implementation detail - Vulpea’s database structure is internal. The public API is functions and data structures, not SQL tables. This allows the backend to evolve without breaking user code.
- Library-first - Vulpea exposes clean abstractions like
vulpea-notethat don’t leak internals. Build applications on top without coupling to implementation details. - Coexistence - Vulpea and org-roam can run side-by-side; they use separate databases and don’t interfere.
For a detailed comparison with org-roam and org-node, see Comparison with Other Libraries.
Vulpea originally started as a layer over org-roam, but v2 is a complete rewrite with its own database and indexing. For the full history and design rationale, see Vulpea v2: a story of breaking up with org-roam.
- 🌳 Files or headings - A note is any org node with an
ID: a whole file, or a single heading inside a larger file - 🚀 Actually async - File watchers, background processing, and an opt-in worker process (
vulpea-db-async-extraction) that parses and writes off the main thread - saving a 100MB file blocks Emacs for about a millisecond - 📊 Optimized queries - Hybrid database schema for fast reads
- 🔌 Extensible - Plugin system for custom extractors and tables
- 🏷️ Rich metadata - Type-aware metadata with automatic coercion
- ⚡ Scales - Tested with 100k+ notes
;; 1. Configure (defaults to org-directory, so often not needed)
;; (setq vulpea-db-sync-directories '("~/org/"))
;; 2. Build database (first time only)
(vulpea-db-sync-full-scan)
;; 3. Enable auto-sync
(vulpea-db-autosync-mode +1)
;; 4. Start using
;; M-x vulpea-find - find and open notes
;; M-x vulpea-insert - insert link to a noteNote: A note is any org node with an ID - a whole file or a single heading. One file can hold many notes: keep every swim session as a heading in swimming.org and each one is a first-class, queryable note. Vulpea indexes exactly these ID-carrying entries; use M-x org-id-get-create to add one to the entry at point.
Optional, but recommended once the basics work:
;; Parse and write in a background process: saving a note - even a
;; 100MB one - blocks Emacs for about a millisecond.
(setq vulpea-db-async-extraction 'full)
;; Skip org-mode-hook during indexing (fine unless you rely on
;; hook-based per-file setup).
(setq vulpea-db-parse-method 'single-temp-buffer)
;; Index only [[bracketed]] links. id: links are always bracketed,
;; so the note graph is unaffected; skips the expensive scan for
;; plain https://... links in prose.
(setq vulpea-db-index-plain-links nil)Also install fd and fswatch - vulpea uses them for fast directory scans and external change detection. Then run M-x vulpea-doctor: it verifies the setup end to end and flags anything that quietly degrades performance (including extractor plugins that bypass the background worker). Details and trade-offs in configuration.
Available on MELPA:
;; Using package.el (after adding MELPA to package-archives)
(package-install 'vulpea)
;; Using use-package
(use-package vulpea)
;; Using straight.el
(straight-use-package 'vulpea)
;; Using elpaca
(elpaca vulpea)
;; Using Doom Emacs - add to packages.el, then run 'doom sync'
(package! vulpea)Doom users: see the Getting Started guide for a complete config.el example and a note about doom env (required for fswatch / fd detection).
Or clone manually:
git clone https://github.com/d12frosted/vulpea(add-to-list 'load-path "/path/to/vulpea")
(require 'vulpea)- Emacs 27.2+
org-mode9.4.4+emacsql4.3.0+ (withemacsql-sqlite-builtin)s1.12+dash2.19+
For best performance, especially with large collections, install these external tools:
| Tool | Purpose | Impact | Install |
|---|---|---|---|
fd | Fast directory scanning | 15× faster than find, critical for polling mode | brew install fd / apt install fd-find / pacman -S fd |
fswatch | Reliable external change detection | Instant detection of git/Dropbox/external changes | brew install fswatch / apt install fswatch / pacman -S fswatch |
Without fswatch, Vulpea falls back to polling (periodic directory scanning). Without fd, polling uses find which is significantly slower. With both tools installed, external changes are detected instantly with near-zero overhead.
| Document | Description |
|---|---|
| Getting Started | Installation, first steps, basic concepts |
| User Guide | Daily usage, interactive commands, working with notes |
| Configuration | All options explained, performance tuning |
| API Reference | Programmatic usage, query functions, data structures |
| Journal Module | Daily notes with widgets and calendar integration (separate package) |
| Plugin Guide | Writing custom extractors for domain-specific data |
| Troubleshooting | Common issues and solutions |
| Comparison | How vulpea compares to org-roam and org-node |
Companion packages that extend Vulpea:
- vulpea-ui - Visual tools for your notes: a per-note sidebar of widgets (outline, backlinks, stats, and more) plus standalone views, with an easy API for your own widgets. Schemas get especially nice treatment here: a sidebar health widget that flags the current note’s violations with one-key fixes, and a collection-wide schema dashboard that shows how every note measures up to the schemas that apply to it.
- vulpea-journal - Daily journaling with calendar integration. Creates one note per day with sidebar widgets for navigation, calendar view, and “on this day” from previous years.
- vulpea-para - The PARA method (Projects, Areas, Resources, Archives) on top of Vulpea. A note’s role is read from its tags rather than its folder, with a self-updating agenda, capture that files itself, and views for areas, projects, and people.
- consult-vulpea - Consult integration for Vulpea. Provides
consult-vulpea-findandconsult-vulpea-insertwith live preview and consult’s narrowing features. - citar-vulpea - Citar integration for Vulpea. Minor mode for managing bibliographic notes, linking citation library entries to Vulpea notes.
- embark-vulpea - Embark actions and export for Vulpea notes.
- vulpea-field - Extension for easily adding new database fields. Compatible with v1 only - it builds on the org-roam-backed
vulpea-db-define-tablemechanism; in v2 use the plugin system instead. - publicatorg - Make your Vulpea notes public.
Applications built on Vulpea:
- vino - Wine cellar management with rich metadata
- claude-orgmode - Connects Claude with org-mode notes
- emacs-org-serve - Go service that reads the Vulpea database directly and serves an Org vault as JSON + PWA to mobile devices
Notable user configurations:
- d12frosted/environment - Personal configuration (13k+ notes), including the task management setup from the Task Management blog series
- jwiegley/dot-emacs
- chrisbarrett/emacs-d
- d4ncer/.emacs.d
- benthamite/dotfiles
v2 is a complete rewrite:
- No org-roam dependency - Standalone library with custom database
- Async-first - Non-blocking updates via file watchers
- Plugin system - Custom extractors with schema versioning
- Performance - Optimized for 100k+ notes
Contributions welcome! See Architecture for design decisions.
Areas where help is needed:
- Performance testing with large collections
- Platform testing (Windows, Linux, macOS)
- Plugin examples
- Documentation improvements
GPLv3
If you enjoy this project, you can support its development via GitHub Sponsors or Patreon.
