Ktor: a Kotlin server and client framework without a container
Framework for quickly creating connected applications in Kotlin with minimal effort
At a glance
- What is it?
- Ktor is JetBrains' coroutine-based HTTP framework for Kotlin. It ships a server, a client and a test host, and leaves logging, serialization and persistence to you. Here is what that costs and what it buys.
- Who is it for?
- Adopt Ktor when your team already writes Kotlin and wants an HTTP layer it can assemble itself: routing, content negotiation and the client pipeline are all installed features, not conventions imposed by a container. Skip it if you need an opinionated stack with built-in persistence and dependency injection, because Ktor's README explicitly declines to choose those for you, and the framework's own answer to a missing piece is a transforming or intercepting function you write.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Ktor actually replaces
Ktor is an HTTP layer for Kotlin, and it is deliberately smaller than a full stack. The README describes it as "an asynchronous framework for creating microservices, web applications and more. Written in Kotlin from the ground up." The last clause is the substance: this is not a Java framework with a Kotlin-friendly API bolted on. Routing, request handling and the client are expressed as Kotlin functions taking lambdas, which is why the README calls the resulting code declarative.
The intended audience is a Kotlin team that wants to choose its own logging, templating, messaging, persistence, serialization and dependency injection. Ktor's principles section lists exactly those categories as things the framework does not constrain. If you have ever fought a framework's built-in ORM or its mandatory DI container, that list reads as a promise. If you have ever spent a sprint wiring up the pieces a framework would have handed you, it reads as a warning. Both readings are correct.
The repository layout reflects the split. ktor-server, ktor-client, ktor-http, ktor-io and ktor-network are separate modules, with ktor-test-server and ktor-test-dispatcher alongside them. You can take the client without the server, or the HTTP types without either.
Pipelines, coroutines and where the code lives
The mechanism the README names is interception. Features are installed into an application through "a unified interception mechanism which allows building arbitrary pipelines." A request enters the pipeline, each installed feature gets a chance to transform or intercept it, and routing is one such feature rather than a privileged core. That is why Ktor's extension points are usually described as writing a function rather than subclassing a base class.
Asynchrony comes from Kotlin coroutines. The README states that the pipeline machinery and API use coroutines, and that all host implementations use asynchronous I/O facilities to avoid thread blocking. The practical consequence is that a handler is a suspend function and the framework does not hand you a thread per request.
Hosting is pluggable through what the README calls a unified hosting API. Ktor applications can run standalone on Netty or Jetty, or inside any servlet container with Servlet 3.0+ API support such as Tomcat. Other hosts can be added through the same API. That is a real architectural commitment: the server engine is a dependency you pick, not a property of the framework.
Testing gets its own environment. Ktor applications can be hosted in a special test environment that emulates a web server without doing networking, which the README says avoids mocking too much while still validating application calls. Integration tests against a real embedded server remain possible.
Installing Ktor and serving a first route
Ktor is published to Maven Central under the io.ktor group, so installation is a dependency declaration in your Gradle build. The README's first step adds the repository and a server engine; the version comes from the $ktor_version property in your build.
repositories {
mavenCentral()
}
dependencies {
implementation("io.ktor:ktor-server-netty:$ktor_version")
}There is also a Ktor Gradle Plugin, published as io.ktor.plugin, which the README says configures the BOM, run tasks and deployment. With it applied, the artifact drops its version because the BOM supplies it.
plugins {
id("io.ktor.plugin") version "3.1.1"
}
dependencies {
implementation("io.ktor:ktor-server-netty")
}The smallest working application installs routing and answers one path. The README's example starts an embedded Netty server on port 8080 and responds to a GET on the root path.
import io.ktor.server.netty.*
import io.ktor.server.routing.*
import io.ktor.server.application.*
import io.ktor.http.*
import io.ktor.server.response.*
import io.ktor.server.engine.*
fun main(args: Array<String>) {
embeddedServer(Netty, 8080) {
routing {
get("/") {
call.respondText("Hello, world!", ContentType.Text.Html)
}
}
}.start(wait = true)
}Run it with the Gradle wrapper. The README states the result: an embedded web server on localhost:8080, routing installed, and "Hello, world!" returned for a GET on the root path.
./gradlew runFor a project rather than a snippet, the README points at start.ktor.io, which generates a first Kotlin HTTP or RESTful application. Separate getting-started pages cover Gradle, Maven and IntelliJ IDEA.
The unopinionated cost, and when that is the wrong trade
Ktor's own principles section is the best statement of its limitation. Logging, templating, messaging, persistence, serialization and dependency injection are all left to the project. The README's framing is that implementing a simple interface is sometimes required, and that otherwise it is "a matter of writing a transforming or intercepting function." That is honest, and it is also work.
If your team has no strong preference on those layers, or has a deadline and no appetite for assembling them, an opinionated stack removes decisions Ktor hands back to you. The README does not claim to be a batteries-included framework, and reading it as one leads to disappointment.
Two narrower cases are worth flagging. First, the Servlet 3.0+ hosting path means the framework's behaviour depends on which host you chose; the README lists Netty, Jetty and servlet containers as options but does not document behavioural differences between them, so that comparison has to come from the ktor.io documentation or from your own deployment. Second, the test environment emulates a web server without networking, which the README presents as a performance and mocking advantage. Anything that depends on real socket behaviour, TLS termination or a proxy in front of the app falls outside what that environment exercises.
Rollback and downgrade procedures are not documented in the README. A MIGRATION_GUIDE.md exists at the repository root, which is the file to read before a major version jump.
Ktor versus Retrofit, and the client side of the split
Retrofit is the comparison people search for, and the difference is structural rather than a matter of taste. Retrofit is an HTTP client built around declarative interfaces: you describe endpoints as annotated methods and it generates the implementation. Ktor's client is part of the same framework as its server, shares the ktor-http and ktor-io modules with it, and is configured through the same pipeline and feature-installation model. A Ktor client call is a function call in a coroutine, not a generated proxy.
That matters most when one codebase speaks both sides. If a Kotlin service calls another Kotlin service, a shared HTTP layer and one mental model for features and interception is the argument for Ktor on both ends. If you are writing an Android app against a third-party REST API and want the smallest possible client surface, Retrofit's interface style is a different and often shorter path, and nothing about Ktor's server makes it the right client for that job.
The repository's module split supports taking only what you need: ktor-client is a separate artifact from ktor-server. The README does not document client setup, so treat ktor.io as the source for that, not this page.
Licence, releases and the upgrade bill
Ktor is Apache-2.0, both in the README badge and in the LICENSE file at the repository root. Apache-2.0 is a permissive licence with an explicit patent grant, and it imposes no copyleft obligation on your application code. It does carry notice and attribution requirements for redistributed source, and THIRDPARTY.md at the repository root is where the bundled third-party components are listed. That is the file to read if your legal review asks what ships inside the artifacts. None of this is legal advice; your own counsel decides.
Maintenance is not in question here. The repository is not archived, and the last push was on 2026-09-21, the same day as the most recent release. Version 3.6.0 was released on 2026-09-18, following 3.5.2 on 2026-08-04 and 3.5.1 on 2026-06-29. That cadence, roughly a minor release every six to eight weeks with patch releases between, is the upgrade cost you are signing up for.
The repository carries a CHANGELOG.md and a MIGRATION_GUIDE.md at the root, plus a VERSION file and a ktor-bom module. The BOM is the practical tool for keeping a multi-module project on one version, and the Ktor Gradle Plugin configures it for you. Budget for reading the migration guide at each minor bump rather than assuming patch-level compatibility across the board.
Editorial conclusion
Adopt Ktor when your team already writes Kotlin and wants an HTTP layer it can assemble itself: routing, content negotiation and the client pipeline are all installed features, not conventions imposed by a container. Skip it if you need an opinionated stack with built-in persistence and dependency injection, because Ktor's README explicitly declines to choose those for you, and the framework's own answer to a missing piece is a transforming or intercepting function you write. Before committing, verify two things against the docs at ktor.io: which host you will deploy on (Netty, Jetty, or a Servlet 3.0+ container such as Tomcat), and whether your test strategy fits the emulated test environment or needs a real embedded server. Then read MIGRATION_GUIDE.md in the repository, because the 3.x line is still shipping minor releases.
Frequently asked questions
What does Ktor mean, and what is Ktor used for?
The README does not give an expansion of the name. It states what the project is: an asynchronous framework for creating microservices, web applications and more, written in Kotlin. It is used to build HTTP services and RESTful applications, and it also ships a client and a test host in the same repository.
Is Ktor better than Spring Boot?
The README does not compare Ktor to Spring Boot, so there is no project position on this. What the README does say is that Ktor imposes few constraints on logging, templating, messaging, persistence, serialization or dependency injection, which is a different default from a batteries-included stack. Whether that is better depends on whether your team wants to choose those layers.
What is Ktor used for?
Per the README, Ktor is an asynchronous framework for creating microservices, web applications and more, written in Kotlin from the ground up. Applications can be hosted standalone on Netty or Jetty, or in any servlet container with Servlet 3.0+ API support such as Tomcat.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ktorio-ktor)