Library / SDK
nmslib/hnswlib avatar
nmslib/hnswlib

hnswlib: a header-only HNSW index for approximate nearest neighbor search

Header-only C++/python library for fast approximate nearest neighbors

5,367 stars863 forksC++Apache-2.0

At a glance

What is it?
hnswlib is a header-only C++ implementation of Hierarchical Navigable Small World graphs with Python bindings, incremental inserts and deletes. It is a good fit when you want an ANN index inside your own process, and a poor fit when you need a managed vector database.
Who is it for?
Adopt hnswlib if you want an in-process approximate nearest neighbor index in C++ or Python and you are willing to tune M and ef_construction yourself. Do not adopt it if you need replication, filtering at scale in Python, or a service you can query over HTTP; the README points to nmslib for other metric spaces and offers no server component.
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 60 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 November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • nmslib/hnswlib5,367 ★ · +35
Star history
Repository2026-09-232026-11-14
nmslib/hnswlib5.3k5.4k

35 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What hnswlib actually solves, and for whom

Exact nearest neighbor search over a large vector set costs a linear scan per query. hnswlib builds a graph index so that a query visits a small fraction of the points and still returns near neighbors. The README describes it as a header-only C++ HNSW implementation with Python bindings, insertions and updates, and lists as highlights: lightweight, header-only, no dependencies other than C++ 11; interfaces for C++, Python, and external support for Java and R; full support for incremental index construction and updating; support for element deletions by marking them; custom user defined distances in C++; and a smaller memory footprint and faster build time than the current nmslib implementation.

The intended reader is an engineer who already has vectors in memory or on disk and wants the index inside the same process. That is the opposite of the managed vector database model, where the index is a service you call. If your application is a Python script that embeds a few hundred thousand vectors, hnswlib is a few lines of setup. If your application needs a query endpoint, sharding, or a durable store that survives a process restart without you writing the file handling, hnswlib leaves those parts to you.

The HNSW graph, M, ef_construction and ef

The algorithm is Hierarchical Navigable Small World search. The index is a layered proximity graph: an upper layer holds few points with long links, lower layers hold more points with shorter links, and a query descends from the top, greedily moving to closer neighbors at each layer. That structure is what makes search sublinear in the number of points, at the cost of returning approximate rather than exact neighbors.

Three parameters govern the trade-off, and the README points to ALGO_PARAMS.md for their full description. M is the maximum number of outgoing connections per node in the graph. ef_construction is the construction-time accuracy and speed trade-off. ef, set through set_ef, is the query-time accuracy and speed trade-off. Raising ef searches more candidates and returns better recall for more time; raising ef_construction builds a better graph for more build time. M changes the memory footprint directly, since every node stores its neighbor lists.

Two details in the README are easy to miss. Inner product is not an actual metric, so an element can be closer to some other element than to itself, which permits a speedup if you remove all elements that are not the closest to themselves. And the Python binding exposes three distances only: squared L2, inner product and cosine. For other spaces the README directs you to nmslib.

Installing hnswlib and running a first query

The Python package is built from source. The pyproject.toml build-system requires setuptools>=42, wheel, numpy>=1.10.0 and pybind11>=2.0, so a C++ toolchain is needed at install time. The setup.py compiles a single extension named hnswlib from python_bindings/bindings.cpp with -std=c++14 preferred and -std=c++11 as fallback. The package version in setup.py is 0.10.0rc2, and the release notes for that candidate say explicitly: do not upload as final 0.10.0 yet.

bash
pip install hnswlib

After installation, the README gives this API shape: hnswlib.Index(space, dim) creates a non-initialized index in space space with integer dimension dim, and init_index(max_elements, M = 16, ef_construction = 200, random_seed = 100, allow_replace_deleted = False) initializes it with no elements. add_items(data, ids, num_threads = -1, replace_deleted = False) inserts a numpy array of vectors with shape N*dim, and knn_query runs the k-nearest-neighbor query.

The README notes that add_items is thread-safe with other add_items calls but not with knn_query, so do not insert and query concurrently on the same index without your own locking. For C++, examples/cpp/ contains the sample programs and the headers live under hnswlib/.

Deletes, updates and the replace_deleted path

hnswlib does not remove a point from the graph when you delete it. mark_deleted(label) flags the element so it is omitted from search results, and unmark_deleted(label) reverses that. The README states that mark_deleted throws an exception if the element is already deleted. The point still occupies its slot, so a workload that churns through inserts and deletes will grow the index until you deal with it.

The mechanism for reclaiming those slots is replace_deleted. You must call init_index with allow_replace_deleted=True, then pass replace_deleted=True to add_items; new elements then take over the slots of deleted ones, which the README says saves memory. This is the reason the 0.10.0rc2 notes care about addPoint(..., int level) being restored: integer levels were being treated as replace_deleted, which would silently route inserts through the replacement path. If you rely on replacement, pin the version and read the release notes for the candidate you install.

Updating an existing label is also supported. add_items with labels that already exist updates their features. The README warns that the update procedure is slower than inserting a new element, but more memory- and query-efficient. resize_index(new_size) changes the maximum capacity, and the README marks it as not thread safe with add_items and knn_query.

Where hnswlib is the wrong tool

The clearest limitation is scope. hnswlib is an index, not a store. There is no server, no replication and no query language. Persistence is file-level: the 0.10.0rc2 notes add streaming saveIndex and loadIndex over std::ostream and std::istream. Python indexes are picklable, according to the README highlights, but that is serialization, not a durability story.

Filtering is the second boundary. The README credits filtering support to version 0.7.0 and says the Python interface for filtering exists, with the note that its performance is limited by the GIL. If your queries are mostly filtered, the Python path may not give you the throughput you expect.

The third boundary is distance. The Python bindings cover squared L2, inner product and cosine. Anything else means either the C++ custom distance interface or a different library. And because inner product is not a metric, its results can be counterintuitive: a point can be closer to another point than to itself, as the README states plainly.

Finally, the version situation. The newest release is a release candidate, v0.10.0-rc.2, and setup.py carries the version 0.10.0rc2 with a comment not to drop the suffix until the stable PyPI release. A team that requires a stable, non-candidate dependency should be aware of what they are installing.

hnswlib compared with FAISS and with nmslib

The comparison people search for is hnswlib versus FAISS. FAISS is a broader library: it offers a range of index families, including IVF and product quantization variants, plus GPU implementations, and it is not header-only. hnswlib implements one algorithm family, HNSW, and ships as headers you drop into a C++ project with no dependencies beyond C++ 11. If you want to pick among index types and tune quantization, FAISS gives you more knobs. If you want a single graph index compiled into your binary with a small dependency surface, hnswlib is the narrower and simpler choice.

The second comparison is inside the same project family. The README says hnswlib has a significantly smaller memory footprint and faster build time than the current nmslib implementation, and it directs users who need spaces other than L2, inner product or cosine to nmslib. So the split is deliberate: hnswlib for the common distances and a lean build, nmslib for a wider set of spaces. Choosing between them is mostly a question of which distances you need.

Licence, build cost and upgrade cost

The licence is Apache-2.0, which is permissive and includes an explicit patent grant. For a header-only library that gets compiled into your binary, the practical question is attribution and notice retention rather than copyleft obligations. This is not legal advice; check the LICENSE file in the repository against your own distribution model.

Build cost is low by design: no dependencies other than C++ 11, and the Python extension compiles a single bindings.cpp. The 0.10.0rc2 notes mention a CMake fix so that the project no longer wipes a caller's CMAKE_CXX_FLAGS, including under add_subdirectory, which matters if you embed hnswlib in a larger CMake build. The same notes add an optional no-exceptions C++ API, where the *NoExceptions methods return Status or StatusOr so the headers compile with -fno-exceptions when configured with -DHNSWLIB_ENABLE_EXCEPTIONS=OFF. Throwing methods remain the default.

Upgrade cost is mostly API surface. The 0.9.0 notes list a behaviour change: an exception is thrown when fewer than k elements are available, so code that previously tolerated a short result set may now raise. The 0.7.0 notes record data race and deadlock fixes in updates and insertion plus a multithreaded stress test, which is a reminder that concurrent mutation of the index was once fragile. If you upgrade, read the release notes for the versions you skip.

Editorial conclusion

Adopt hnswlib if you want an in-process approximate nearest neighbor index in C++ or Python and you are willing to tune M and ef_construction yourself. Do not adopt it if you need replication, filtering at scale in Python, or a service you can query over HTTP; the README points to nmslib for other metric spaces and offers no server component. Before committing, verify that the version you install is the release candidate 0.10.0rc2 rather than a stable 0.10.0, and check whether your build needs -DHNSWLIB_ENABLE_EXCEPTIONS=OFF for a -fno-exceptions toolchain.

Frequently asked questions

How do I install hnswlib?

Install it with pip, which builds the extension from source using the pyproject.toml build requirements: setuptools>=42, wheel, numpy>=1.10.0 and pybind11>=2.0. A C++ compiler is required because setup.py compiles python_bindings/bindings.cpp into a module named hnswlib.

What is hnswlib?

It is a header-only C++ implementation of Hierarchical Navigable Small World graphs for approximate nearest neighbor search, with Python bindings and support for incremental insertion, updates and deletions. The README lists no dependencies other than C++ 11.

What is HNSW and how does it work?

HNSW is the graph structure hnswlib builds: a layered proximity graph that a query descends from the top, moving greedily to closer neighbors at each layer. M controls the maximum outgoing connections per node, ef_construction the build-time trade-off, and ef the query-time one, as described in ALGO_PARAMS.md.

What is a navigable small world graph?

It is the graph model behind the HNSW index in hnswlib, where nodes are linked to nearby points across multiple layers so that a greedy walk reaches a near neighbor in few steps. The README refers to ALGO_PARAMS.md for the parameter description.

Official sources

  1. License: Apache-2.0
  2. nmslib/hnswlib on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nmslib-hnswlib.svg)](https://hysenlabs.com/projects/nmslib-hnswlib)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/nmslib-hnswlib.svg)](https://hysenlabs.com/projects/nmslib-hnswlib)

Was this useful?