Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Vector storage: is sqlite-vec really the best fit for Synapse?

FieldValue
Date finalised2026-06-02
AuthorRômulo Febasi <romulo@febasi.com.br> (analysis assisted by Claude Code)
ScopeOwner-prompted critical review (2026-06-02) of the ADR-008 decision to adopt sqlite-vec. Survey of the 2026 alternative options: LanceDB, SurrealDB embedded, DuckDB + VSS, vectorlite, usearch, Qdrant embedded: measured against Synapse’s actual constraints, not generic benchmarks.
Statusaccepted: confirms ADR-008 stays as written; registers vectorlite as the documented upgrade path for v0.7+ if we hit the flat-scan ceiling
InputsADR-003 (rusqlite bundled); ADR-008 (this week’s decision); v0.5 brief §2.2; live walks of asg017/sqlite-vec, lancedb/lancedb, surrealdb/surrealdb, 1yefuwang1/vectorlite, unum-cloud/usearch repositories; 2026 benchmark write-ups on slashdot, peerspot, thedataquarry, lancedb.com; Alex Garcia’s roadmap statements on the sqlite-vec issue tracker.
Out of scopeMigrating FTS5, the audit trail, Workspace::tx, the pending queue, or any other SQLite-resident feature out of SQLite; this brief evaluates the vector storage slot only.

Executive summary

Three honest answers to the owner’s question:

  1. For Synapse’s actual workload (≤ 10k entities per workspace, federation handles scale by chunking), sqlite-vec is the right pick. It is recent, maintained, and fits our existing .synapse/index.db model cleanly. ADR-008 stays as written.
  2. For a 2026 greenfield project starting from scratch with no SQLite baggage, the answer would be LanceDB. It is the architectural option born for the workload. We are not greenfield. Migrating from SQLite to LanceDB costs more than the upside delivers at our ceiling: Workspace::tx, FTS5 ranking, audit trail, pending queue, federation registry are all tightly coupled to the SQLite engine. Re-implementing them is a v1.0-shaped task, not a v0.5 spike.
  3. The honest upgrade path exists. If a Synapse user ever exceeds ~100k entities per workspace and the flat-scan latency becomes visible, the drop-in replacement is vectorlite (HNSW-based, ~10× faster searches than sqlite-vec’s flat scan, same loadable- extension shape, still SQLite). Registered as the v0.7+ pre-staged ticket so the option is not lost.

1. The constraint set that actually matters here

The vector storage choice has to satisfy seven hard constraints before any benchmark number is relevant. Most “is X better than Y” articles online ignore these because they are project-specific:

ConstraintSourceWhat it eliminates
Atomic FS + index transactions (Workspace::tx)BR-6, ADR-003 §ConsequencesAny backend without a transaction model that composes with the filesystem write
Append-only audit trail living next to the indexBR-12.3, ADR-013Any backend that requires a separate process or separate storage mount
FTS5 ranking already shipped in 121 testsv0.4 codebaseAny backend that forces a re-implementation of full-text from zero
Single binary, no daemonBR-1, BR-12, ADR-018’s “no second runtime” threadAnything that requires localhost:<port>
Cross-platform: aarch64+x86_64 macOS, aarch64+x86_64 Linux, x86_64 Windowsv0.4 release matrixAnything that ships only on a subset of OSes
Liberal OSS license (MIT or Apache 2.0)Synapse is MITAnything that ships proprietary or AGPL
Workspace ceiling 10k entities (federation chunks beyond)v0.5 brief §6.3Anything optimised exclusively for ≥ 1M vectors at the cost of complexity

Anything that satisfies all seven is a candidate. The list of candidates that pass the gate is short.

2. The candidate matrix

The matrix below grades each option against the Synapse constraint set, not against synthetic benchmarks. Each row ends with the yes/no on whether a v0.5 migration to that option would pay back.

OptionWhat it isHard-no for Synapse?Soft-no for Synapse?Worth migrating from sqlite-vec?
sqlite-vec 0.1.9Alex Garcia’s loadable SQLite extension; flat brute-force scan; ~1.5 MB native code; rusqlite integration documented. Author roadmap: v1.0 within a year, then maintenance mode. ANN index (“eventually”) still in design.-Flat scan is the v0.5 ceiling; documented at 10k entitiesbaseline
vectorlite 0.2.x (beta)hnswlib-based HNSW index packaged as a SQLite loadable extension. 2×–40× faster search, 10× faster inserts vs sqlite-vss according to the author’s bench (2025). Still beta as of 2026.-Beta status + smaller maintainer; HNSW tuning adds knobs we don’t need at 10k entitiesNo for v0.5 (too early); yes if we ever exceed ~100k vectors per workspace
LanceDB embeddedApache Arrow-based vector lakehouse. Rust core. In-process. Has Tantivy-backed FTS, hybrid search, rerankers, S3 backing. ~50 MB extra binary. 1.5M IOPS bench 2026. Multi-modal (vectors + tables + text + images).-Would force re-implementing Workspace::tx, the pending queue, the audit trail, the federation registry, and all FTS5 callers because LanceDB has no SQL transactions in the SQLite sense; it is Arrow-native, columnar. Atomic write-after-write semantics are different.No: migration cost is v1.0-shaped, not v0.5. Right answer if we were greenfield in 2026. We are not.
SurrealDB embeddedMulti-model DB (graph + document + relational + vector + KV + time-series + geospatial). Rust-native. Embedded + server. Custom query language (SurrealQL).-Same as LanceDB plus: replaces SQL entirely. Loses 100% of our existing SQL tests + migrations + the queries 21 commits in v0.4 just wrote. Conceptually attractive (graph + vector + KV in one engine maps onto Synapse’s data model nicely) but the migration is a complete reskinning.No: even more costly than LanceDB. Reconsider only on a v2.0 reset.
DuckDB + VSS extensionColumnar OLAP database with a vector extension. Embedded. Multi-platform.-Wrong workload shape: DuckDB is analytical (read-heavy aggregations) not transactional (one row, one write). Synapse is transactional. DuckDB also breaks Workspace::tx for the same reasons LanceDB does.No: DuckDB is the answer for a different product.
usearchSingle-file HNSW index library by Unum. ~1 MB. C++/Rust/multi-language. No storage layer: just the index.-Would have to wire its own storage and we’d lose SQLite’s transaction bindingNo as a standalone replacement; could complement sqlite-vec if we ever wanted HNSW without leaving SQLite, but vectorlite already does that and ships as a SQLite extension
Qdrant embedded modeReal vector DB that has an embedded crate. Rust-native. HNSW.-Same daemon-shaped split as Ollama: heavy binary growth, separate API surface, ~80 MBNo: same reason we rejected Ollama-as-runner for embeddings
sqlite-vector by sqlite.aiCommercial-ish (sqliteai.com) vector extension; HNSW.License unclear (BSL? Commercial?)-No until license clarity
Tantivy + custom vectorLucene-style FTS engine in Rust. Quickwit underpins it. Not a vector store on its own.-We’d add Tantivy alongside SQLite + a separate vector layer. Three storage engines, three transaction surfaces, three failure modesNo: we’d be inventing LanceDB’s stack ourselves
Hand-rolled flat scan + SIMD cosinePure Rust, no dep.-Reinvents sqlite-vec for no upside; lacks the ANN index path we’d want at scaleNo

The matrix collapses to three real options: stay on sqlite-vec, upgrade to vectorlite (HNSW within the SQLite shell), or migrate to LanceDB (different shell entirely).

3. Cross-check vs the architectural promises Synapse already made

Synapse’s data model is eight entity types + tags + links + FTS + pending + audit + provenance + federation cache, all atomic per Workspace::tx. The matrix below tabulates how much code each backend would force us to re-write, taking the v0.4 codebase as the baseline (Cargo.toml at synapse 0.4.0, 121 lib tests, 10k+ LOC).

SubsystemLOC todayStays on sqlite-vecMoves to vectorliteMoves to LanceDB
Workspace::tx (atomic FS + SQLite transaction)~150unchangedunchangedrewrite: different transaction surface
FTS5 ranking + snippet~120unchangedunchangedreplace with Tantivy: different ranker, snippet format, tests
Audit trail (.synapse/audit.ndjson lives outside the DB but the pending queue and the payload_sha256 integrity check are SQLite-backed)~450unchangedunchangedrewrite the queries: Arrow columnar reads, no SQL
Pending queue~530unchangedunchangedrewrite
Federation registry + manifest cache (separate SQLite DB at ~/.config/synapse/workspaces.db)~560unchangedunchangedmigrate or keep on SQLite alongside: two DBs, two query languages
Schema migrations (0001..0004)~200 (incl. SQL)unchangedunchangedrewrite as Arrow-native migrations
FTS5 MATCH … ORDER BY rank callers~80 in core::search, cli/at, mcpunchangedunchangedrewrite all of them
core::reindex (4 migration tables, 6 entity types)~310unchangedunchangedrewrite
Net delta~0 lines~30 lines (FFI to vectorlite or migration script)~2,400 lines rewritten + ~100 tests rewritten

Migrating to LanceDB is a v1.0-shaped commitment in a v0.5 cycle. Migrating to vectorlite is a ~30-line swap (the loadable-extension boundary is the same as sqlite-vec). Staying on sqlite-vec costs zero.

4. Where each option really beats sqlite-vec

The honest read on each alternative, not biased by what we already have:

LanceDB

  • Multi-modal (vectors + images + tables + Parquet-importable) by design. We do not need this today. If Synapse ever ships a syn entity import <csv> for 10M-row enterprise CRM dumps, LanceDB becomes the right answer.
  • Tantivy-backed FTS is more flexible than SQLite FTS5 (custom analyzers, faceting, BM25 score tuning). FTS5 is enough for our workload size; Tantivy would matter at corpora 100× ours.
  • 1.5M IOPS on cloud-backed storage; we are local-first, the IOPS number is meaningless for us.
  • Native hybrid search with query_type="hybrid", but we are building RRF ourselves on top of three signals (FTS + vector + graph), so LanceDB’s hybrid doesn’t subsume our SYN-86 ticket.

vectorlite

  • HNSW index → sub-millisecond search on millions of vectors. The one real performance win over sqlite-vec for large corpora.
  • Same SQLite shell, same load_extension shape, same FFI integration pattern we’re already taking with sqlite-vec in SYN-81.
  • Beta status as of 2026: author is one maintainer, less mature than sqlite-vec’s ecosystem.

SurrealDB

  • The data model fits Synapse better than SQL does: graph edges + documents + KV + vectors are exactly what entities + links + tags
    • embeddings need. If we were starting from scratch in 2026 with Synapse’s spec in hand, SurrealDB is the architectural option to consider seriously.
  • But we are not greenfield. We have 121 tests pinning SQL behaviour.

5. The conditional logic that would force a re-evaluation

Three triggers would re-open this decision. Recording them so the next reader does not have to re-do the survey:

TriggerWhat to do
A real user workspace exceeds ~100k entities and reports flat-scan latency on syn searchMigrate to vectorlite (HNSW). ~30 lines of FFI changes. Same SQL queries. Same FTS5. No business logic change. Pre-staged ticket: SYN-203 (file in v0.7 milestone when created).
Synapse decides to support multimodal capture (images, audio embeddings, large attachments)Evaluate LanceDB seriously. It owns multimodal natively; bolting it onto SQLite is unhealthy. This would be a v2.0 conversation.
sqlite-vec project goes inactiveSwitch to vectorlite (same shell) immediately. Synapse already had the same risk play out with tower-lsp → tower-lsp-server and managed; the rerun is documented in ADR-018.
Synapse opens an enterprise CRM / SaaS-integration import path with 1M+ rowsMigrate to LanceDB: same conversation as the multimodal trigger above, just for a different scale axis.

6. Risk of staying on sqlite-vec: the parts the ADR didn’t fully

The ADR-008 §Consequences lists three risks. The exhaustive read:

RiskSeverity nowMitigation already in place
Flat scan O(N) becomes visible at ≥ 50k vectors per workspaceLowBrief §6.3 caps the v0.5 workspace at 10k entities; federation chunks beyond
sqlite-vec author single-maintainer (Alex Garcia) goes inactiveMediumSwitch to vectorlite (same shell); C extension is ABI-stable so the source can be vendored under src/index/vendor/ if upstream disappears
ANN index promised “soon” never materialisesLowDoesn’t block v0.5; if it never lands, vectorlite is the upgrade path
sqlite-vec v1.0 introduces breaking changes during the maintenance handoffMediumWe pin a specific version + take FFI direct path (per ADR-008 production wiring decision), insulating us from crate-level API churn
rusqlite ^0.31 vs our 0.39 collisionLowResolved in ADR-008 by FFI-against-C-extension path; no Rust crate dependency

None of these justify a v0.5 migration away from sqlite-vec.

7. Recommendation

Confirm ADR-008 as written. No change to v0.5. The decision matrix says sqlite-vec is the right call for our workload size, codebase shape and constraint set. The alternatives are either wrong-workload (DuckDB), too-early (vectorlite beta), or greenfield-only (LanceDB, SurrealDB).

Two follow-ups that this report recommends filing:

IDWhatWhen
SYN-203 (placeholder)Document vectorlite migration path as the v0.7+ swap; vendor sqlite-vec C source under src/index/vendor/ so we are insulated from upstream churnOpen ticket now, no milestone: moves into v0.7 when that milestone exists
ADR amendmentAppend to ADR-008 §Consequences: “If a workspace ever exceeds 50k indexed entities, switch to vectorlite via the same load_extension FFI path: no business-logic change required.”Inline edit to ADR-008: small enough to do now

8. References