Kdrant

A Kotlin client for Qdrant: REST by default, gRPC when you need it, the same API above both.

Gradleimplementation("io.github.nacode-studios:kdrant-transport-rest:2.1.0")
kdrant.kt
val qdrant = Kdrant(host = "localhost", port = 6333)qdrant.use { client -> client.createCollection("articles") { vector { size = 1_536; distance = Distance.COSINE } } client.upsert("articles", wait = true) { point(id = 1) { vector(embedding) payload("title" to "Introduction", "language" to "en") } }}
The product

A Kotlin client for the Qdrant vector database. Every operation is a suspend function, and collections, points and filters are declared through a type-safe DSL. Two transport engines, REST and gRPC, sit behind one interface, and the REST engine runs on the JVM and eight Kotlin/Native targets.

Create a collectionJava
QdrantClient.javaofficial client
var client = new QdrantClient(    QdrantGrpcClient.newBuilder("localhost", 6334, false)        .build()); ListenableFuture<CollectionOperationResponse> f =    client.createCollectionAsync("articoli",        VectorParams.newBuilder().setSize(1536)            .setDistance(Distance.Cosine).build());f.get();  // ...and then handle ExecutionException
Dependenciesgrpc-netty-shadedprotobuf-javagrpc-protobufguava
Kdrant.ktKdrant
val qdrant = Kdrant(host = "localhost", port = 6333) qdrant.use { client ->  client.createCollection("articles") {    vector { size = 1_536; distance = Distance.COSINE }  }}
Dependenciesktor-client-corekotlinx-serializationsuspendDSLREST over Ktor, gRPC optional
Gradleimplementation("io.github.nacode-studios:kdrant-transport-rest:2.1.0")Maven Central · Apache-2.0
the difference, in code

Qdrant's official JVM client is built for Java: every call hands back a ListenableFuture, requests are assembled with protobuf builders, and the wire is decided for you, with Netty on your classpath whether you needed it or not. Kdrant does the same work through an API that reads like Kotlin. Operations are suspend functions with cooperative cancellation and timeouts, and CancellationException always propagates. Collections, points, payloads and filters are declared through scoped DSLs. Errors are a sealed hierarchy, so the compiler checks that you handled all of them. The protocol is the caller's to choose. The default engine is REST on Ktor and kotlinx-serialization, and it keeps gRPC, protobuf and Netty out of the project. The gRPC engine is a separate artifact, worth adding when throughput or streaming is the bottleneck. Switching between them changes one line, because both sit behind the same transport interface: adding the second engine required no change to the core. Both engines answer to the same behavioural test suite, run against a real Qdrant over each protocol. Fourteen operations that Qdrant serves over HTTP only, among them telemetry, metrics and snapshot transfer, fail on the gRPC engine by saying so rather than degrading quietly. In 2.1 the REST engine runs everywhere the core does: the JVM plus eight Kotlin/Native targets across iOS, macOS, Linux and Windows. Until 2.0 those targets received the models and the DSLs with nothing to put a request on the wire. The engine is now chosen per platform, and the behavioural suite that runs on the JVM is run from a Linux binary and a macOS one against a real Qdrant, because a library that compiles is not yet a library that works. The gRPC engine stays on the JVM, because it is grpc-java. 2.1 also adds what running it in production takes. Beside the master key you can use a JWT narrowed to read-only, to one collection, or to a payload filter, which is how one customer's search is kept away from another customer's points; a refusal arrives as a typed exception rather than a generic error. The OpenTelemetry module produces one span per operation, over both engines, without a payload or a vector ever reaching an attribute. The migration module moves a collection to a new embedding model: it resumes after an interruption, and it moves the alias only once a verification has actually run. Coverage includes the /points/query endpoint in all its modes (nearest, hybrid fusion, recommend, discover, context, batch, groups), sparse and multiple vectors, scroll, payload and vector management, aliases, snapshots, cluster and sharding, and retry policies. Modules ship for Spring Boot, Spring AI, LangChain4j, Koog, Micrometer, OpenTelemetry and migrations.

Scope
Open sourceKotlinKotlin MultiplatformVector databaseRAG
Approach

What we did

01Design of the public API and of the DSLs
02The transport interface and both engines, REST on Ktor and gRPC
03Migrating the core to Kotlin Multiplatform
04The behavioural test suite shared between the engines
05Spring Boot, Spring AI, LangChain4j, Koog, Micrometer and OpenTelemetry modules
06Publishing to Maven Central and semantic versioning
Highlights
+Operations are suspend functions, with cooperative cancellation
+Type-safe DSL for collections, points, payloads and filters
+Errors as a sealed hierarchy, checked at compile time
+Two engines behind one API: REST on Ktor, gRPC optional
+Staying on REST keeps gRPC, protobuf and Netty off your classpath
+A complete client, engine included, on the JVM and eight Kotlin/Native targets
+Scoped JWTs beside the master key, over both engines
Results
The second engine required no change to the core
Thirty-two behavioural tests run over both protocols and from a native binary
The move to multiplatform changed no public API
Eleven modules on Maven Central under io.github.nacode-studios
First search 37 ms after process start, from a 42 MB GraalVM binary
API documentation generated with Dokka
Resources
Open on GitHubVisit the siteRepository

Like what we build?

Let us talk about your next project