The graph adds roughly 2*m edges per point on layer 0, plus upper layers
The HNSW graph is not free. On layer 0, each point stores up to 2*m neighbor links because edges are bidirectional, so a point with m=16 has up to 32 links. Each link is an integer point ID, typically 4 or 8 bytes depending on the ID type and the internal representation. That is roughly 128 to 256 bytes per point on layer 0 alone, before you count the upper layers. The upper layers add a fraction on top - each point has a probability of appearing in each higher layer, and the expected total number of links across all layers is layer_0_links times a factor that depends on m, roughly 1.1 to 1.3 for typical m. So for a collection of 100 million points with m=16 and 4-byte IDs, the graph alone is on the order of 13 to 17 GB. That is on top of the raw vectors (100M * 768 * 4 bytes = ~307 GB for float32) and on top of the payload indexes and point metadata.
The reason this matters for in-memory capacity planning is that teams routinely size RAM by counting vector bytes and then are surprised when the node runs out of memory. The graph is not a small overhead - for typical m values it is a meaningful fraction of the total, and it grows linearly with point count. It also grows with m, so raising m to improve recall has a direct memory cost that is easy to underestimate. Payload indexes are a third component that is easy to forget: keyword indexes, range indexes, and full-text indexes all consume memory, and their size depends on the cardinality and the number of indexed fields. Point metadata - the IDs, the version numbers, the tombstones - also adds a per-point overhead. When you are planning a node's RAM, the correct estimate is the sum of all of these, not just the vectors. A useful rule of thumb for an in-memory collection is to add 30 to 60 percent to the raw vector bytes to account for the graph, payload indexes, and metadata, with the exact figure depending on m and on the number of indexed fields.
Layer 0: up to 2*m links per point, each link an integer ID (4 or 8 bytes).
Upper layers: add roughly 10-30 percent on top of layer 0 for typical m values.
Graph memory scales linearly with point count and with m, so raising m for recall costs memory directly.
Payload indexes: separate structures whose size depends on field cardinality and count.
Point metadata: IDs, versions, and tombstones add a per-point overhead.
Planning rule: for in-memory collections, add 30-60 percent to the raw vector bytes to account for graph, indexes, and metadata.
The trade-off is that the graph overhead is the price of sub-linear search. Without the graph, every query would be a linear scan, which is unacceptable at scale. With the graph, you pay memory proportional to m and to point count, in exchange for logarithmic search. The common mistake is sizing RAM by the vector data alone and then discovering that a 100M-point collection needs substantially more than the vector bytes suggest. The second mistake is raising m to fix recall without accounting for the memory increase, especially on a node that is already close to capacity. The third mistake is forgetting the payload indexes, which on collections with many indexed fields can be a significant fraction of the total. The alternative to carrying the graph in RAM is to put it on disk, either entirely or with the quantized vectors inline; that trades the memory cost for I/O, which may be acceptable depending on the latency SLO. Version note: the exact graph memory overhead depends on the ID representation and on the internal storage layout, both of which have changed across Qdrant releases. The upper-layer multiplier and the way links are stored may differ, so a plan that was accurate on one version may be off on another. Measure the actual memory usage on your version rather than relying on a fixed multiplier.
Version-dependent: the internal representation of graph links and point IDs has changed across Qdrant releases, as has the upper-layer structure. The memory overhead per point is therefore not a fixed constant across versions. If you are planning a large in-memory deployment, measure the actual RSS of a representative collection on your version rather than extrapolating from a formula, and re-measure after upgrades that touch the storage engine.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience