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.
You size a node for 50M vectors and it runs out of RAM. Explain what components you probably forgot and how you would redo the estimate.
A teammate raises m from 16 to 48 to improve recall. Explain the memory impact and whether it is worth it.
You need to fit a 30M-vector collection on a node with 128 GB of RAM. Walk through the full memory estimate, including vectors, graph, and payload indexes, and decide whether it fits.
Your collection uses 20 percent more RAM than your estimate predicted. List the likely sources of the discrepancy and how you would confirm each.
Design a capacity plan for a fleet of nodes serving a 200M-vector collection with an in-memory configuration. Include the graph, payload indexes, and headroom, and specify the node size and count.
You must reduce the memory footprint of an in-memory collection by 25 percent without changing the recall target. Walk through the levers (m, quantization, payload indexes, on-disk placement) and the impact of each.
Derive the memory overhead of the HNSW graph as a function of m, point count, and ID representation, and explain how the upper-layer factor depends on the level distribution. Where does the model typically undercount?
You are designing a capacity planning tool for a vector search fleet. Describe the model, the inputs it needs, and how you would validate its predictions against production telemetry.