Vectorlite: HNSW Vector Search Inside SQLite, Loaded as an Extension
Fast, SQL powered, in-process vector search for any language with an SQLite driver
At a glance
- What is it?
- Vectorlite is a loadable SQLite extension that wraps hnswlib behind a virtual table, so any language with a SQLite driver gets approximate nearest neighbor search. It is beta software, prebuilt for five platforms, and its index lives in memory unless you save it.
- Who is it for?
- Adopt Vectorlite if you already keep metadata in SQLite and want approximate nearest neighbor search without running a separate vector service, and if you can accept beta status and the fact that the HNSW index is held in memory until you explicitly save it. Do not adopt it if you need exact results, a server you can query over the network, or a stable API across upgrades.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Vectorlite solves, and who it is actually for
SQLite stores rows, not vectors. If your application already keeps documents, products or messages in a SQLite file, adding semantic search normally means standing up a separate vector database, syncing embeddings into it, and keeping two stores consistent. Vectorlite removes that second store by loading an HNSW index into the same process as SQLite and exposing it as a virtual table.
The intended user is a developer whose data already lives in SQLite and whose language has a SQLite driver. Because Vectorlite is a runtime-loadable extension rather than a library binding, the same compiled artifact works from Python, Node.js, Go, Rust or the sqlite3 CLI. The README states it is pre-compiled for Windows-x64, Linux-x64, MacOS-x64 and MacOS-arm64, and distributed as Python wheels and npm packages, which is the shortest path to a working setup.
It is not a general purpose vector database. There is no server, no network protocol and no query planner beyond what SQLite offers. The project is also in beta, and the README warns that breaking changes are possible, so the API surface should be treated as movable.
How the virtual table and HNSW index fit together
Vectorlite registers a SQLite virtual table module. A table declared with `using vectorlite(...)` carries a vector column of type `float32[N]` and an `hnsw(...)` argument list that configures the underlying hnswlib index. The README lists distance_type (default l2), ef_construction (default 200), M (default 16), random_seed (default 100) and allow_replace_deleted (default true) as the tunable parameters, plus the required max_elements.
Search is invoked through a function called `knn_search` inside the WHERE clause, paired with `knn_param(query_vector, k)`. That construction is what lets SQLite hand the query down to the index rather than scanning rows. The README notes that a rowid filter written as `rowid in (...)` is pushed down into the HNSW graph traversal when SQLite is at least 3.38, which the project calls a metadata filter: you compute a candidate rowid set from ordinary SQL columns, then run vector search restricted to that set.
Vectors cross the SQL boundary as BLOBs via `vector_from_json()` and `vector_to_json()`, and `vector_distance()` is available as a standalone function. That last one matters because it makes brute force search expressible in plain SQL with an ORDER BY and a LIMIT, returning exact results at the cost of scanning every row. The virtual table trades that accuracy for speed, which is the central design trade-off in the project.
Installing Vectorlite and running a first search
The README gives two one-line installs. For Python, `pip install vectorlite-py`; for Node.js, `npm i vectorlite`. There is no server to start and no daemon to configure.
pip install vectorlite-pyOnce installed, the extension has to be loaded into a connection before any of its functions exist. In the sqlite3 CLI the README uses `.load` with the platform-appropriate file extension:
.load path/to/vectorlite.[so|dll|dylib]
select vectorlite_info();The `vectorlite_info()` call is the confirmation step: the README says it prints the version and the best SIMD target chosen by Highway at runtime. If that returns a row, the extension is live.
Creating a table and inserting vectors follows the same pattern the README demonstrates. The vector column declares its dimension, and the hnsw arguments set the index capacity:
create virtual table my_table using vectorlite(my_embedding float32[3], hnsw(max_elements=100));
insert into my_table(rowid, my_embedding) values (0, vector_from_json('[1,2,3]'));
insert into my_table(rowid, my_embedding) values (1, vector_from_json('[2,3,4]'));
insert into my_table(rowid, my_embedding) values (2, vector_from_json('[7,7,7]'));A query then asks for the k nearest neighbors of a query vector. The result columns are rowid and distance, and distance is not part of the table schema; it is produced by the knn_search expression:
select rowid, distance from my_table
where knn_search(my_embedding, knn_param(vector_from_json('[3,4,5]'), 2));For a first real use, the rowid is the join key. The README explicitly suggests storing a vector's metadata elsewhere, for example in another table, and relating it back by rowid. That is the intended architecture: SQLite holds the text and attributes, Vectorlite holds the embeddings, and rowid connects them.
The in-memory index is the constraint that shapes deployment
The README is direct about this: the index is always held in memory, and persistence is explicit. A table is not durable by virtue of being a virtual table. To keep an index you write it out with an operation row:
insert into {table_name}(operation, path) values ('save', '/path/to/index.bin');
insert into {table_name}(operation, path) values ('load', '/path/to/index.bin');Loading replaces the table's current in-memory index, and the README states that on any error the existing index is left unchanged. That is a sensible failure mode, but it also means the save and load cycle is something you have to build into your application lifecycle. A process that crashes between the last insert and the save loses the index, even though the surrounding SQLite rows may be intact. The README does not document rollback beyond that error behavior, so treating save as a checkpoint you control is the safer reading.
Memory is the second constraint. max_elements is required at table creation, and the README does not describe what happens when you exceed it. Since the index lives in RAM, capacity planning is a function of vector count, dimension and the HNSW parameters you chose, not of disk space. This is the point where Vectorlite stops being a drop-in replacement for a database and becomes a component you size deliberately.
Approximate results are the third. HNSW is an approximate index; the README contrasts it with the brute force approach built on `vector_distance`, which it says returns 100 percent accurate results. If your workload needs exactness, the virtual table is the wrong tool and the plain-table ORDER BY pattern is the right one.
Vectorlite compared with sqlite-vec and sqlite-vss
The README names sqlite-vec and sqlite-vss as similar projects and states that Vectorlite's vector query is significantly faster than both. It also publishes a benchmark section, though the numbers there are the maintainer's own and come with the caveat that the README attributes the SIMD speedup measurement to a specific machine, an i5-12600KF with AVX2, where the project's implementation is reported as 1.5x to 3x faster than hnswlib's for dimensions of 256 or more.
The architectural difference is worth stating plainly. Vectorlite is built on hnswlib and exposes HNSW parameters such as M, ef_construction and random_seed directly in the table declaration, and it supports index serialization compatible with hnswlib, meaning an index file created by hnswlib can be loaded by Vectorlite. That makes it attractive if you already have HNSW tuning experience or existing hnswlib index files. The distance types are the ones hnswlib provides: l2 (squared l2), cosine and ip, with the README explicitly saying it does not recommend inner product.
The trade-off is surface area. Exposing graph parameters and serialization means more decisions for the user, and the beta label means those decisions may need revisiting. A project that hides HNSW behind a simpler interface would ask less of you. Vectorlite's position is that the control is the feature, and the README supports that with example files for HNSW parameters, metadata filtering and index serialization.
Licence, packaging and what upgrading costs
Vectorlite is Apache-2.0, and pyproject.toml declares `license = {text = "Apache-2.0"}` for the Python package. That is a permissive licence with an explicit patent grant, which matters more than usual here because the extension links hnswlib and Google's Highway library. Anyone redistributing a binary should check the licences of those dependencies themselves; this is not legal advice, and the repository's LICENSE file is the authoritative text.
The packaging story has a wrinkle worth knowing. pyproject.toml declares `requires-python = ">=3.14"` while the classifiers list Python 3.9 through 3.13. Those two statements are inconsistent, and a reader should treat the classifiers as the more plausible intent while verifying against the actual wheel metadata before pinning a version. The build uses scikit-build-core with Ninja and a vcpkg toolchain, and setup.py is described in its own docstring as a stub kept for backward compatibility, delegating to the PEP 517 backend.
Upgrade cost is dominated by the beta warning. The README repeats that there could be breaking changes, and the released versions are v0.1.0 and v0.2.0 from mid-2024 while pyproject.toml already reports version 0.3.0, so the packaged version leads the tagged releases. For a pinned dependency this is manageable; for a long-lived index format it means you should test a load of an old index file after any upgrade rather than assume compatibility.
Maintenance signals are mixed in a specific way. The last push to the default branch was on 2026-09-13, two days before this writing, and the repository is not archived. The tagged releases, however, are from 2024, so activity is in the working tree rather than in versioned releases.
Editorial conclusion
Adopt Vectorlite if you already keep metadata in SQLite and want approximate nearest neighbor search without running a separate vector service, and if you can accept beta status and the fact that the HNSW index is held in memory until you explicitly save it. Do not adopt it if you need exact results, a server you can query over the network, or a stable API across upgrades. Before committing, verify that your SQLite build is at least 3.38 if you want rowid predicate pushdown, that the wheel or npm package exists for your platform, and how you will persist and reload the index with the save and load operations.
Frequently asked questions
Does Vectorlite work with Python?
Yes. The README states Vectorlite is distributed as Python wheels and can be installed with pip install vectorlite-py, and the bindings directory plus pyproject.toml confirm the Python package is built with scikit-build-core.
What is the difference between Vectorlite and using SQLite alone?
Plain SQLite can already do exact nearest neighbor search if you store embeddings as BLOBs and order by vector_distance, but that scans every row. Vectorlite adds a virtual table backed by an hnswlib HNSW index, which the README says is much faster at the cost of approximate rather than exact results.
Is the Vectorlite index saved to disk automatically?
No. The README states the index is always held in memory and must be persisted explicitly by inserting a row with operation 'save' and a path, then restored later with operation 'load'.
Community notes