Kotlin
A concise multiplatform language developed by JetBrains
The Ktor roadmap and previews
As in previous years, we have been working on the Ktor roadmap, and we want to say thank everyone for their contributions and feedback to help us prioritize the roadmap! The OpenAPI and WebRTC support is already in preview since the Ktor 3.3.0 release. Check out the What’s New section for a full overview of Ktor 3.3.0.
🚀 Get started with ktor
Ready to explore Ktor? Start building your next project today with our interactive project generator at start.ktor.io. Your feedback and contributions are always welcome!
🔗 Get Started With Ktor | 📢 Join the Community on Reddit and Slack
Ktor Library Improvement Process
The Ktor team is always looking for feedback, and therefore we fully develop everything in the open, including creating feature proposals similar to KEEPs but for Ktor. This is called KLIP, or Ktor Library Improvement Process, and it can be found on GitHub. So keep an eye out for future proposals in case you’ve missed it, and please provide any feedback you might have.
(Open)API Documentation
API Documentation, currently one of the most requested features, has gone into development. 🎉 In Ktor 3.3.0 it was included in an early preview so you can provide early feedback. Check the OpenAPI KLIP, or check out the Ktor OpenAPI Template project.
Ktor can automatically provide an OpenAPI model from analyzing your code at compile-time, and can simply be set up from Gradle. The Ktor Gradle Plugin has a new openapi configuration which can be used to provide OpenAPI information, and setup project-related configurations. The plugin currently only supports Kotlin 2.2.20. Additionally we also need to add a Maven dependency for the ktor-server-openapi
module, or ktor-server-swagger
depending on your preference.
plugins { kotlin(libs.plugins.kotlin) alias(libs.plugins.ktor) } ktor { @OptIn(OpenApiPreview::class) openapi { target = project.layout.projectDirectory.file("api.json") title = "My Service" summary = "What it does" description = "A longer description of the service" version = "1.0.0" // contact, termsOfService, license... } } dependencies { implementation(libs.ktor.server.core) implementation(libs.ktor.server.openapi) }
}
To find out more about the api documentation support, check out the proposal or try it yourself in your project using the template project.
Service Discovery
In distributed systems, service discovery is a critical part of the distributed system. As servers become available, clients need to be able to discover them. The Service Discovery plugin eliminates the need to manually register the services, and resolve the client. The plugin offers a unified abstraction layer over popular discovery mechanisms (Consul, Kubernetes, Zookeeper, Eureka) while offering both client-side and server-side discovery patterns. This allows you to configure service discovery in a Ktor -and Kotlin-idiomatic way.
In the example below, we configure the ServiceDiscovery
plugin to automatically register our sample-service
on port 8080
with the consul service registry on localhost:8500
.
install(ServiceDiscovery) { consul { connection { host = "localhost" port = 8500 } registration { serviceName = "sample-service" instanceId = "sample-service:$host:$port" port = 8080 } } }
Another service needs to be able to communicate with the sample-service
. In a distributed system, it doesn’t matter which instance we use, so we rely on the service registry to resolve the serviceName
into a registered instanceId
. The HttpClient
ServiceDiscovery
plugin allows us to conveniently do so.
val client = HttpClient { install(ServiceDiscovery) { consul { connection { host = "localhost" port = 8500 } } } } client.get("service://sample-service")
The HttpClient
is configured with the ServiceDiscovery
plugin connected to the same Consul service registry as our server example. Once configured we can use service://name
to resolve a service within our distributed system. In this case the sample-service
.
To find out more about the service discovery support, check out the proposal, and please leave any feedback.
WebRTC
Real-time peer-to-peer communication is becoming increasingly useful for various applications, ranging from video calls to multiplayer and collaborative tools. We’re working on bringing WebRTC Client support to Ktor with a unified, multiplatform API that works seamlessly across browsers, Android, and potentially other platforms.
Signaling (WebSocket, HTTP, etc.) still manually needs to be managed but we’re focusing on making the peer-to-peer connection part as smooth as possible. Ktor 3.3.0 supports JS/Wasm and Android platforms, with more platforms like JVM, iOS, Native coming. Support for an experimental Rust-based WebRTC client is also planned. This could pave the way for integrating Rust components in other areas of Ktor. More details can be found in the KLIP, or the full stack KMP Ktor Video Chat example.
A WebRtcClient
is created by providing the engine instance and configuring the platform-specific configuration similar to HttpClient
.
val jsClient = WebRtcClient(JsWebRtc) { defaultConnectionConfig = { iceServers = listOf(WebRtc.IceServer("stun:stun.l.google.com:19302")) } } val androidClient = WebRtcClient(AndroidWebRtc) { context = appContext // provide Android context defaultConnectionConfig = { /* Same default config*/ } }
WebRTC clients need to create an RTC peer-to-peer connection which they establish using the Interactive Connectivity Establishment (ICE). After the peers have connected, they can send and receive data from each other using the channels.
val jsConnection = jsClient.createPeerConnection() jsConnection.addIceCandidate(WebRtc.IceCandidate(candidateString, sdpMid, sdpMLineIndex)) jsConnection.awaitIceGatheringComplete() jsConnection.dataChannelEvents.collect { event -> when (event) { is Open -> println("Another peer opened a chanel: ${event.channel}") is Closed -> println("Data channel is closed") is Closing, is BufferedAmountLow, is Error -> println(event) } }
To find out more about the WebRTC support check out the proposal, and please leave any feedback you may have.
gRPC: Powered by kotlinx-rpc
It’s finally here: gRPC support in Ktor! But with a catch. The kotlinx-rpc library is doing all the heavy lifting of bringing gRPC support to Ktor. kotlinx-rpc is dedicated to bringing you the best gRPC experience in Kotlin. Let’s define a new GrpcService
in a common module and then use it on both the server side and client side.
@Grpc interface GrpcService { suspend fun sayHello(request: HelloRequest): HelloResponse }
Our server side implementation might look like this, and we can register it in our Ktor Application
using the grpc
DSL.
interface GrpcServiceImpl : MyService { suspend fun sayHello(request: HelloRequest): HelloResponse { return HelloResponse { content = "Hello, ${request.name}" } } } fun Application.installGrpc() = grpc { registerService<MyService> { MyServiceImpl() } }
Depending on your use -cases or existing systems, you might prefer working with .proto
files instead. The interface GrpcService
can also be defined from .proto
, and it’ll generate the same interface as above. Allowing the same implementation, and Ktor usage.
syntax = "proto3"; package io.ktor; service MyService { rpc sayHello(HelloRequest) returns (HelloResponse); }
You can also use generated messages from .proto
files.
message HelloRequest { string name = 1; } message HelloResponse { string content = 1; }
Alternatively, you can also use KotlinX’s @Seriazable
or your preferred serialization techniques.
Support for Apple, Linux, beyond JVM is planned. Check our kotlinx-rpc for more details.
Koog Integration
The new Ktor Koog Plugin makes it easy for you to create agentic services with Ktor and Koog. It aims to provide a deep integration between Koog and Kotlin’s AI ecosystem.
fun Application.module() { install(Koog) routing { get("/execute/{prompt}") { val prompt = call.parameters.getOrFail("prompt") val output = aiAgent(customStrategy(), GPT4_1, prompt) call.respond(HttpStatusCode.OK, output) } } }
Dependency Injection
Dependency Injection support was released earlier this year, as discussed in last year’s roadmap post. In the OpenAPI Documentation feature we’re introducing a compiler plugin to Ktor to generate documentation at compile time. This is the perfect opportunity to further enhance our dependency injection support with compile-time verification and provide better support for other platforms.
fun Application.dependencies() = dependencies { provide<HikariDataSource> { hikariSource() } provide<R2dbcDatabase> { exposed(get()) } provide<MyService>(::MyServiceImpl) }
🚀 Get started with Ktor 3.3.0
Ready to explore Ktor 3.3.0? Start building your next project today with our interactive project generator at start.ktor.io. Your feedback and contributions are always welcome!
We want to thank everyone in the community for your support and feedback, as well as for reporting issues.
🔗 Get Started With Ktor | 📢 Join the Community on Reddit and Slack