What's new in Ktor 3.3.0
Ktor 3.3.0 delivers new capabilities across server, client, and tooling. Here are the highlights for this feature release:
Ktor Server
Custom fallback for static resources
Ktor 3.3.0 introduces a new fallback()
function for static content, allowing you to define custom behavior when a requested resource is not found.
Unlike default()
, which always serves the same fallback file, fallback()
gives you access to the original requested path and the current ApplicationCall
. You can use this to redirect, return custom status codes, or serve different files dynamically.
To define custom fallback behaviour, use the fallback()
function within staticFiles()
, staticResources()
, staticZip()
, or staticFileSystem()
:
LastModified and Etag headers for static content
Ktor 3.3.0 introduces support for ETag
and LastModified
headers for static resources. When the ConditionalHeaders
plugin is installed, you can process conditional headers to avoid sending the body of content if it hasn't changed since the last request:
The values are calculated dynamically based on each resource and applied to the response.
You can also use a predefined provider, for example to generate a strong ETag
using the SHA‑256 hash of the resource content:
Development mode auto-reload limitations
In Ktor 3.2.0, the introduced support for suspend module functions caused a regression where auto-reload stopped working for applications that use blocking module references.
This regression remains in 3.3.0 and auto-reload continues to work only with suspend
function modules and configuration references.
Examples of supported module declarations:
We plan to restore support for blocking function references in a future release. Until then, prefer a suspend
module or configuration reference in development
mode.
HTTP/2 cleartext (h2c) support
Ktor 3.3.0 introduces support for HTTP/2 over cleartext (h2c) for the Netty engine, which allows HTTP/2 communication without TLS encryption. This setup is typically used in trusted environments, such as local testing or private networks.
To enable h2c, set the enableH2c
flag to true in the engine configuration. For more information, see HTTP/2 without TLS.
Ktor Client
SSE response body buffer
Until now, attempting to call response.bodyAsText()
after an SSE error failed due to double-consume issues.
Ktor 3.3.0 introduces a configurable diagnostic buffer that allows you to capture already-processed SSE data for debugging and error handling.
You can configure the buffer globally when installing the SSE plugin:
Or per call:
As the SSE stream is consumed, the client maintains a snapshot of the processed data in an in-memory buffer (without re-reading from the network). If an error occurs, you can safely call response?.bodyAsText()
for logging or diagnostics.
For more information, see Response buffering.
WebRTC client
This release introduces experimental WebRTC client support for peer-to-peer real-time communication in multiplatform projects.
WebRTC enables applications such as video calls, multiplayer gaming, and collaborative tools. With this release, you can now use a unified Kotlin API to establish peer connections and exchange data channels across JavaScript/Wasm and Android targets. Additional targets such as iOS, JVM desktop, and Native are planned for future releases.
You can create a WebRtcClient
by selecting an engine for your platform and providing configuration, similar to HttpClient
:
Once created, the client can establish peer-to-peer connections using Interactive Connectivity Establishment (ICE). After negotiation completes, peers can open data channels and exchange messages.
For more details on usage and limitations, see the WebRTC client documentation.
Updated OkHttp version
In Ktor 3.3.0, the Ktor client's OkHttp
engine has been upgraded to use OkHttp 5.1.0 (previously 4.12.0). This major version bump may introduce API changes for projects that interact directly with OkHttp. Such projects should verify compatibility.
Unified OkHttp SSE session
The OkHttp engine now uses the standard API for Server-Sent Events (SSE), replacing the previously introduced OkHttpSSESession
. This change unifies SSE handling across all client engines and addresses the limitations of the OkHttp-specific implementation.
Gradle plugin
OpenAPI specification generation
Ktor 3.3.0 introduces an experimental OpenAPI generation feature via the Gradle plugin and a compiler plugin. This allows you to generate OpenAPI specifications directly from your application code at build time.
It provides the following capabilities:
Analyze Ktor route definitions and merge nested routes, local extensions, and resource paths.
Parse preceding KDoc annotations to supply OpenAPI metadata, including:
Path, query, header, cookie, and body parameters
Response codes and types
Security, descriptions, deprecations, and external documentation links
Infer request and response bodies from
call.receive()
andcall.respond()
.
Configure the extension
To configure the extension, use the openApi
block inside the ktor
extension in your build.gradle.kts file. You can provide metadata such as title, description, license, and contact information:
Generate the OpenAPI specification
To generate the OpenAPI specification file from your Ktor routes and KDoc annotations, use the following command:
Serve the specification
To make the generated specification available at runtime, you can then use the OpenAPI or SwaggerUI plugins.
The following example serves the generated specification file at an OpenAPI endpoint:
For more details about this feature, see OpenAPI specification generation.
Shared
Updated Jetty version
The Jetty server and client engines have been upgraded to use Jetty 12. For most applications, this upgrade is fully backward-compatible, but client and server code now leverage the updated Jetty APIs internally.
If your project uses Jetty APIs directly, be aware that there are breaking changes. For more details, refer to the official Jetty migration guide.