A small, hand-written C++ gRPC client for Qdrant, packaged as a Bazel module.
The protobuf schema under qdrant/proto/ is not hand-written — it is
vendored verbatim from the upstream Qdrant repository:
- Source:
lib/api/src/grpc/proto/in qdrant/qdrant v1.18.2 (downloaded from the release tarball, not a git checkout) - Scope: the full public, client-facing API — the
Points,Collections,Snapshots, rootQdrant(health check), and standardgrpc.health.v1.Healthservices with all their messages. Cluster-internal service protos (raft, shard transfer, node-to-node point/collection ops) are deliberately excluded; a client never calls them. - Local deviations (the only ones): import paths are rewritten to the
qdrant/proto/prefix so the files build from the workspace root, andqdrant.protois trimmed of its internal-service imports. Seeqdrant/proto/README.mdfor the exact file list and the step-by-step upgrade procedure. - License: the vendored protos are © Qdrant, licensed under Apache 2.0 (copied from the upstream repository).
This module's version (MODULE.bazel, currently 1.18.2) tracks the
upstream Qdrant release the protos were vendored from.
Because the full schema is vendored, all generated message and stub types
(qdrant::QueryPoints, qdrant::ScrollPoints, quantization configs,
sparse/named vectors, …) are available to downstream code even where the
convenience wrapper below does not expose them.
The hand-written public surface is the qdrant::QdrantClient class
(qdrant/qdrant_client.h):
EnsureCollection— create a cosine-distance collection (optionally recreating it) and invoke an optionalcreate_indexes(collection)callback at the point a fixed payload-index step used to run.CollectionExists— existence check, with an optional deadline.CreateFieldIndex— create a payload field index of a givenqdrant::FieldType(idempotent). The caller picks which fields to index.UpsertPoints— batch caller-builtqdrant::PointStructvalues (id + vector + payload) into a single Upsert RPC, returning per-call timing. The caller owns point construction; the client only handles transport.Search— runs a caller-builtqdrant::SearchPointsrequest (vector, filter, limit, payload/vector selectors, search params) and returns the rawqdrant::ScoredPointresults, with optional per-call timing.
Add it to your MODULE.bazel:
bazel_dep(name = "qdrant_cpp_client", version = "1.18.2")Then depend on the library and include the header:
cc_binary(
name = "my_tool",
srcs = ["my_tool.cc"],
deps = ["@qdrant_cpp_client//:qdrant_client"],
)#include <qdrant/qdrant_client.h>
qdrant::QdrantClient client("localhost:6334");
client.EnsureCollection(
"my_collection", /*dimensions=*/768, /*recreate=*/false,
[&](std::string_view collection) {
client.CreateFieldIndex(collection, "symbol", qdrant::FieldTypeKeyword);
});To use parts of the API the wrapper does not cover, depend on
@qdrant_cpp_client//:qdrant_cc_proto (messages) and
@qdrant_cpp_client//:qdrant_grpc (service stubs) directly.
The repo builds with C++20 (set in .bazelrc).
bazel build //...
bazel test //...//:qdrant_client_compile_test is a compile-only smoke test that confirms the
public header is self-contained (it includes only the generated message
classes, no generated gRPC service stubs).
Resolved from the Bazel Central Registry:
grpc1.80.0protobuf33.4 — capped here because gRPC 1.80.0 still loads@protobuf//bazel:upb_proto_library.bzl, which protobuf removed in 34.x. Bump the two together.abseil-cpp,rules_cc,rules_proto
See MODULE.bazel for exact versions.