If you build on the JVM and want to use is the client you'd actually want to write Kotlin against:
Coroutine-first — every operation is asuspendfunction, with cooperative cancellation and timeouts
Type-safe DSLs for collections, points, payloads, and filters
Small footprint — a pure-Kotlin REST engine on Ktor +kotlinx-serialization; no gRPC, Netty, or protobuf
Typed errors — a sealedKdrantExceptionyou can handle exhaustively
It's stable (1.1.0, SemVer) and published to Maven Central under io.github.nacode-studios.
Quick start
Requires JDK 17+. One dependency:
dependencies {
implementation("io.github.nacode-studios:kdrant-transport-rest:1.1.0")
}
Spin up Qdrant locally:
docker run -p 6333:6333 qdrant/qdrant
Connect, create a collection, upsert, search:
val qdrant = Kdrant(host = "localhost", port = 6333) {
apiKey = System.getenv("QDRANT_API_KEY") // omit for a local, unauthenticated node
requestTimeout = 5.seconds
}
qdrant.use { client ->
client.createCollection("articles") {
vector { size = 1_536; distance = Distance.COSINE }
}
client.upsert("articles", wait = true) {
point(id = 1) {
vector(embedding) // your List<Float> from any embedding model
payload("title" to "Introduction", "lang" to "en", "year" to 2026)
}
}
val hits = client.search("articles") {
query(queryVector)
limit = 5
filter { must { "lang" eq "en" } }
}
}
Kdrant stores and searches vectors you already have — it does not generate embeddings.
A filter DSL that reads like Kotlin
Qdrant's full filtering model, expressed declaratively:
val query = filter {
must {
"lang" eq "en"
"year" gte 2024
"price" between 10.0..99.0
}
should {
matchAny("tag", "featured", "promo")
geoRadius("location", GeoPoint(lon = 13.40, lat = 52.52), radius = 5_000.0)
}
mustNot { "archived" eq true }
}
Decode results straight into your types
@Serializable data class Article(val title: String, val lang: String)
val articles: List<Hit<Article>> = qdrant.searchAs<Article>("articles") {
query(queryVector); limit = 5
}
val first: Article? = articles.firstOrNull()?.payload
Hybrid search (dense + sparse)
The modern /points/query engine is fully supported. Fuse several prefetch sources with Reciprocal Rank Fusion for true dense + keyword hybrid search:
val hits = qdrant.search("articles") {
prefetch { query(denseVector); using = "text"; limit = 50 }
prefetch { querySparse(indices, values); using = "keywords"; limit = 50 }
rrf() // or dbsf()
limit = 10
}
recommend / discover / context, grouped and batch search, multi-vectors, and a Flow-based scroll are all there too.
Building RAG? It plugs in.
Kdrant ships first-class integrations so you don't wire it by hand:
Spring Boot starter — an auto-configuredQdrantClientbean
Spring AI — implementsVectorStore
LangChain4j — implementsEmbeddingStore
There's a runnable
io.github.nacode-studios:kdrant-transport-rest:1.1.0Feedback is very welcome — especially on API ergonomics. If there's something you'd want from a Kotlin-native Qdrant client, open an issue and let's talk.
SOCIAL SHARE CARD GENERATOR