Two embedded engines with different briefs — where each one wins, verified against Nano v4.31.1
SQLite is the most deployed database in the world, and deservedly so: it is in-process, zero-configuration, exhaustively tested, and backed by a file format and tooling ecosystem that has been stable for two decades. For a very large number of applications it is the correct answer, and staying on it is a legitimate engineering decision rather than a failure to scale.
HeliosDB Nano is a different embedded engine with a different brief: relational SQL and native vector search in one in-process library, with the option to expose the same data directory over the PostgreSQL and MySQL wire protocols when more than one process needs to reach it. Start embedded; add server access as the application grows. This page compares the two honestly, including the places where Nano is currently the weaker choice.
Every Nano claim below was checked against the v4.31.1 release (tagged 2026-09-07). Where a capability is partial, scoped to one access path, or behind a non-default build feature, the table says so.
Evaluating HeliosDB Lite instead? Lite is a separate product tier with its own licence, feature set, and deployment model — it is not Nano with more features, and nothing on this page describes it. See HeliosDB Lite.
Nano is split into two columns because several capabilities exist on only one of its access paths. Reading the two as a single merged column will overstate what either one does.
| Capability | SQLite core | SQLite + ext | Nano embedded | Nano server |
|---|---|---|---|---|
| In-process and server access | In-process only | Third-party server wrappers | Rust API, Python, REPL | PostgreSQL, MySQL, REST |
| Reader / writer concurrency | WAL: many readers, one writer | Unchanged | MVCC reads + autocommit writes | Real per-connection concurrency |
| Independent explicit transactions | One writer at a time | Unchanged | Not safe — shared slot | Yes, per connection |
| Vector search | None | Varies by extension | HNSW built in (default) | Same engine, any client |
| Full-text search | FTS5 + BM25 + stemming | Ships in amalgamation | BM25, no stemming | Same |
| Branching & historical queries | None | File-level snapshot tools | Branches + AS OF reads | Same |
| Row-level security | None | Application-level only | Yes | Not reachable over the wire |
| Encryption at rest | None (public build) | SEE (paid) / SQLCipher | AES-256-GCM, off by default | Same |
| Replication | None built in | External WAL-level tools | Reaches logical WAL (v4.8.0+) | Primary / standby / observer |
| SQL dialect, API & file format | Its own dialect, one file, huge ecosystem | Same format | PG-flavoured SQL, data directory | Existing PG/MySQL clients |
| Maturity & operational record | Decades in production | Varies by extension | Young, active correctness work | Same codebase |
Every cell keyed to a fuller note below — read the note before treating a short cell as the whole story, especially for the three rows marked not safe / not reachable / none on Nano's side.
src/storage/mvcc.rs).VECTOR(n) columns and <-> / <=> / <#> distance operators. The default path is in-process HNSW; product quantization and RocksDB-backed persistent HNSW require building with --features vector-persist, which is not in the default feature set.bm25() ranking function. Nano's PostgreSQL-shaped surface (tsvector, tsquery, @@, ts_rank / ts_rank_cd) lowercases on Unicode word boundaries and does not stem; phrase and proximity operators parse but degrade to a bag of terms; @@ is true if any query term is present; setweight() and rank weights are accepted and ignored; and CREATE INDEX ... USING gin is accepted as DDL but not consulted at runtime, so @@ walks matching rows. Nano documents this itself in docs/compatibility/fts.md.MERGE BRANCH moves rows but performs no conflict detection — it is last-writer-wins, with no warning if both sides touched the same row. Fork, validate, discard, and re-apply the validated SQL to main is the safe pattern. Time-travel reads are bounded by retained versions (1 hour minimum retention by default, configurable, garbage-collected by VACUUM VERSIONS) and are not a substitute for backups.fips build feature. Encryption seals values, not keys — table names, column names, row ids, and timestamps remain readable on disk, as do HNSW graph snapshots and backup dumps. Enabling it seals new writes only; it does not retroactively seal data already written..sqlite file in place — existing files come across as a one-shot conversion through the converter bundled in the Nano repository. Nano is statically typed where SQLite is dynamically typed, so inserts SQLite accepts can be rejected.The table scrolls sideways on narrow screens, so the four limits that most often decide this comparison are repeated here:
BEGIN…COMMIT blocks safely. Server mode is the supported answer.MERGE BRANCH does not detect conflicts. It is last-writer-wins and silent. Discard branches and re-apply validated SQL instead.Two cells in the table are deliberately non-specific. The SQLite + extensions entry for vector search does not name an extension or an index type, because index support in that ecosystem moves and differs by project and version — verify against the extension and release you actually plan to ship. The comparison is otherwise drawn from Nano's own source and compatibility documentation.
This is where a port from SQLite most often goes wrong, so it is worth stating plainly.
What works on the embedded API: concurrent reads, and writes issued as single autocommit statements. MVCC means readers are not blocked by a writer.
What does not work on the embedded API: two callers holding overlapping explicit BEGIN…COMMIT transactions. Explicit transaction state lives in one process-global slot per handle and is shared across every clone of that handle, so independent, overlapping transactions from separate threads are not safe. There are lower-level session primitives in the crate, but they are internal plumbing rather than a supported public API, and they are not a workaround we recommend. A public embedded session API is roadmap, not shipped.
Supported options today, in order of preference:
BEGIN and the COMMIT.One further distinction worth keeping straight: the local crash-recovery WAL is always on and is separate from the logical WAL used for replication. Embedded writes inside explicit transactions have reached the logical WAL since v4.8.0; before that they did not.
Outgrowing SQLite is not inevitable, and these are not edge cases.
.sqlite file.AS OF TIMESTAMP answers "what did this look like before that job ran" without restoring anything, within the retention window.psql muscle memory carry over at the connection layer. Wire-protocol compatibility is about connectivity, not full semantic parity — byte-order-only collation and embedded-only RLS are two concrete current gaps.# Rust / CLI
cargo install heliosdb-nano
# Python, in-process binding
pip install heliosdb-nano-embedded
# Scratch database in memory
heliosdb-nano repl --memory
# Or initialise a persistent data directory
heliosdb-nano init ./heliosdb-data
heliosdb-nano repl --data-dir ./heliosdb-data
From Python, the binding calls the embedded engine directly — no subprocess, no wire protocol:
import heliosdb_nano
db = heliosdb_nano.EmbeddedDatabase("./heliosdb-data") # or .in_memory()
db.execute("CREATE TABLE notes (id INT, title TEXT, body TEXT)")
db.execute_many(
"INSERT INTO notes (id, title, body) VALUES ($1, $2, $3)",
[(1, "First", "hello"), (2, "Second", "world")],
)
db.query("SELECT * FROM notes WHERE title = $1", ("First",))
db.create_vector_store("emb", 3)
db.insert_vectors("emb", [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
db.vector_search("emb", [1.0, 0.0, 0.0], k=1)
# Stop the embedded process first — one directory, one process
heliosdb-nano start \
--data-dir ./heliosdb-data \
--port 5432 \
--auth scram-sha-256 --password "$HELIOSDB_PASSWORD"
# Connect with any PostgreSQL client
psql -h 127.0.0.1 -p 5432 -U postgres
# Or enable the MySQL listener alongside it
heliosdb-nano start --data-dir ./heliosdb-data --mysql
Keep the Nano version identical across the embedded-to-server switch. Changing access mode and engine version at the same time makes any resulting problem much harder to attribute.
CREATE TABLE docs (
id SERIAL PRIMARY KEY,
title TEXT,
body TEXT,
embedding VECTOR(1536)
);
CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops);
-- k-NN
SELECT title, embedding <-> '[0.15, 0.25, ...]' AS distance
FROM docs ORDER BY distance LIMIT 10;
-- Full-text, PostgreSQL-shaped (unstemmed; see the table above)
SELECT title, ts_rank_cd(to_tsvector(body), to_tsquery('heliosdb')) AS rank
FROM docs
WHERE to_tsvector(body) @@ to_tsquery('heliosdb')
ORDER BY rank DESC LIMIT 10;
There is no in-place path: Nano does not read the SQLite file format. Conversion is a one-shot export through the converter bundled in the Nano repository, followed by re-testing your queries against Nano. Budget real time for the type-affinity difference — Nano is statically typed, so values SQLite silently accepted into a column can be rejected — and do not assume SQLite-specific statements translate one-for-one. INSERT OR REPLACE and ON CONFLICT DO UPDATE in particular are not equivalent: the former deletes and reinserts the row, which resets unspecified columns to their defaults, while the latter updates in place.
See the migration guides for the current step-by-step.
We do not publish a head-to-head SQLite benchmark, and this page deliberately carries no throughput figures. Relative performance between an embedded MVCC engine and SQLite depends heavily on write pattern, transaction size, durability settings, and whether the workload touches vector or text search at all — a single number would mislead more than it informed. Measure both on your own workload. Published HeliosDB figures, with their fixtures, are on the benchmarks page.
HeliosDB Nano adds CREATE EXTENSION hdb_code for SQL-callable LSP, the WITH CONTEXT clause for grounded RAG, eight ingestion adapters (incl. Docling-backed PDF / Office / audio / image), an in-process embedder, and a native MCP server reachable from Claude Code, Cursor, Continue, Codex, and Aider. Learn more →
Get started with HeliosDB in minutes. Open source, free to use.