ensureCollection creates the collection when it is absent, and when it is present it verifies the
vectors and returns. Everything else the collection carries goes unchecked: HNSW, quantization,
optimizers, strict mode, the payload indexes without which the filters do not perform, and after Tier 10
the memory tier and the storage datatype.
So the ordinary deployment story ends the same way every time. A collection was created a year ago by a
call that has since changed, or by a colleague, or from the dashboard, and the code that describes it
and the collection that exists have quietly diverged. Nothing anywhere reports the difference. The first
evidence is a query that is slower in production than the same query in staging, and the reason is a
payload index that only staging ever had.
The answer is the diff, not the mutation. kdrant plan reads a declared collection and the live one and
prints what differs. kdrant apply performs the part Qdrant can change in place, which is optimizers,
HNSW, quantization, strict mode and missing payload indexes, and refuses the rest by name: vector size
and distance are a rebuild, and a tool that hides a rebuild behind a word like apply is a tool that
deletes somebody's collection.
The refusals are the design. They are also what keeps this honest rather than an impression of
Terraform, and there is one more rule that does the same job: no state of its own. No lock file, no
recorded history, no notion of a previous plan. The server is the state, and a tool that keeps a second
copy of it is a tool that will one day be confidently wrong about a collection somebody changed by hand.
This is where ensureCollection was always heading, and where kdrant-migrate stops: migration answers
what to do when the vectors have to change, and this answers everything that does not need one.
Exit criterion: kdrant plan reports the difference between a declared collection and a live one across
vectors, HNSW, quantization, optimizers, strict mode and payload indexes; kdrant apply performs every
difference Qdrant can apply in place and refuses each one it cannot, naming the reason and the rebuild it
would need; both run against a real Qdrant in CI.
ensureCollectioncreates the collection when it is absent, and when it is present it verifies thevectors and returns. Everything else the collection carries goes unchecked: HNSW, quantization,
optimizers, strict mode, the payload indexes without which the filters do not perform, and after Tier 10
the memory tier and the storage datatype.
So the ordinary deployment story ends the same way every time. A collection was created a year ago by a
call that has since changed, or by a colleague, or from the dashboard, and the code that describes it
and the collection that exists have quietly diverged. Nothing anywhere reports the difference. The first
evidence is a query that is slower in production than the same query in staging, and the reason is a
payload index that only staging ever had.
The answer is the diff, not the mutation.
kdrant planreads a declared collection and the live one andprints what differs.
kdrant applyperforms the part Qdrant can change in place, which is optimizers,HNSW, quantization, strict mode and missing payload indexes, and refuses the rest by name: vector size
and distance are a rebuild, and a tool that hides a rebuild behind a word like apply is a tool that
deletes somebody's collection.
The refusals are the design. They are also what keeps this honest rather than an impression of
Terraform, and there is one more rule that does the same job: no state of its own. No lock file, no
recorded history, no notion of a previous plan. The server is the state, and a tool that keeps a second
copy of it is a tool that will one day be confidently wrong about a collection somebody changed by hand.
This is where
ensureCollectionwas always heading, and wherekdrant-migratestops: migration answerswhat to do when the vectors have to change, and this answers everything that does not need one.
Exit criterion:
kdrant planreports the difference between a declared collection and a live one acrossvectors, HNSW, quantization, optimizers, strict mode and payload indexes;
kdrant applyperforms everydifference Qdrant can apply in place and refuses each one it cannot, naming the reason and the rebuild it
would need; both run against a real Qdrant in CI.