Introduction
Kona is a full-stack web framework for the JVM. You write application code in Kotlin or Java (or both in the same project). The framework itself is implemented in Kotlin, and every public API is designed so Java call sites stay natural: there is no Kotlin-only ceremony required to boot an app, register routes, or look up services.
Kona takes inspiration from productive application frameworks in other ecosystems (notably Laravel and Almasix). From here on, these docs describe Kona on its own terms: its names, boot sequence, HTTP stack, and tooling.
Who these docs are for
Section titled “Who these docs are for”You should already be comfortable with a programming language, with classes and interfaces, and with HTTP at a high level: methods such as GET and POST, status codes such as 200 and 404, headers, and JSON bodies. You do not need to have used any web framework before. Every Kona term is defined the first time it appears, and each concept page explains why the piece exists and when it runs.
A complete Kona app
Section titled “A complete Kona app”Before the vocabulary, here is a complete program. It starts Kona, registers one service, defines one route, and listens on port 4000.
import org.konaframework.core.Applicationimport org.konaframework.core.Konaimport org.konaframework.core.ServiceProviderimport org.konaframework.http.HttpKernelimport org.konaframework.http.HttpServiceProviderimport org.konaframework.http.KonaHttpServerimport org.konaframework.http.Responseimport org.konaframework.http.Router
class Greeter(private val greeting: String) { fun greet(name: String) = "$greeting, $name"}
class AppServiceProvider : ServiceProvider { override fun register(app: Application) { app.container.singleton(Greeter::class.java) { Greeter("Hello") } }
override fun boot(app: Application) { val greeter = app.resolve(Greeter::class.java) app.resolve(Router::class.java).get("/hello/{name}") { request -> Response.json(mapOf("message" to greeter.greet(request.attributes["name"].toString()))) } }}
fun main(args: Array<String>) { val app = Kona.create(args) .providers(HttpServiceProvider(), AppServiceProvider()) .boot() KonaHttpServer(app.resolve(HttpKernel::class.java), "127.0.0.1", 4000).start()}import org.konaframework.core.Application;import org.konaframework.core.Kona;import org.konaframework.core.ServiceProvider;import org.konaframework.http.HttpKernel;import org.konaframework.http.HttpServiceProvider;import org.konaframework.http.KonaHttpServer;import org.konaframework.http.Response;import org.konaframework.http.Router;import java.util.Map;
public final class Main { public static final class Greeter { private final String greeting; public Greeter(String greeting) { this.greeting = greeting; } public String greet(String name) { return greeting + ", " + name; } }
public static final class AppServiceProvider implements ServiceProvider { @Override public void register(Application app) { app.getContainer().singleton(Greeter.class, c -> new Greeter("Hello")); }
@Override public void boot(Application app) { Greeter greeter = app.resolve(Greeter.class); app.resolve(Router.class).get("/hello/{name}", request -> Response.json(Map.of("message", greeter.greet(String.valueOf(request.getAttribute("name")))))); } }
public static void main(String[] args) { Application app = Kona.create(args) .providers(new HttpServiceProvider(), new AppServiceProvider()) .boot(); new KonaHttpServer(app.resolve(HttpKernel.class), "127.0.0.1", 4000).start(); }}A request to GET /hello/kona returns {"message":"Hello, kona"}. The rest of this page names each piece you just saw.
Vocabulary
Section titled “Vocabulary”- Application (
org.konaframework.core.Application): The object that represents your running project. It knows its base path (the directory that holds.env,config/, and usually your sources), owns a container and a config store, and keeps the list of service providers. There is normally one per process. See Application & providers. - Service provider (
org.konaframework.core.ServiceProvider): A small class with two methods,registerandboot, that plugs a feature into the application.registerdescribes how to build services;bootruns startup work once every provider has registered. Kona’s own HTTP layer arrives asHttpServiceProvider; your code typically lives in anAppServiceProvider. - Container (
org.konaframework.core.Container): A registry that knows how to create objects. You bind a type to a factory (“to make aGreeter, call this lambda”), then resolve the type wherever you need it. The container can also build ordinary classes on its own by calling their constructor and resolving each parameter. See Container. - Config (
org.konaframework.core.Config): A tree of settings addressed with dotted keys such asapp.nameordatabase.pool.size. Values come from built-in defaults, files inconfig/, and code. See Config & env. - Env (
org.konaframework.core.Env): Read access to environment variables, with an optional.envfile as a fallback. Real process variables always take precedence over the file. - Router (
org.konaframework.http.Router): Maps an HTTP method plus a URL pattern (for exampleGET /hello/{name}) to a handler: a function that takes aRequestand returns aResponse. - Middleware (
org.konaframework.http.Middleware): A function that sits in front of a handler. It receives the request and anexthandler, and may change the request, change the response, or answer immediately without callingnext(for example, rejecting a request with401). - HTTP kernel (
org.konaframework.http.HttpKernel): The single entry point that turns aRequestinto aResponse: it runs global middleware, asks the router for a matching route, runs that route’s middleware and handler, and converts any thrown exception into an error response. - kona (global CLI): creates applications —
kona new my-app. - grind (app-local CLI): lives in each project as
./grind—./grind serve,./grind make:controller,./grind migrate. - Cadence (
org.konaframework.cadence): the database layer — connections, a query builder, models, relations, and migrations. See Cadence overview.
The lifecycle, start to finish
Section titled “The lifecycle, start to finish”Knowing when each piece runs makes the rest of the docs easier to follow.
- Process start. Your
maincallsKona.create(args). Kona decides the base path: the value of a--base=/some/dirargument if you passed one, otherwise the current working directory. - Bootstrap. When you call
.boot()on the builder, Kona creates theApplication, loads.envfrom the base path (if the file exists), seedsapp.name,app.env, andapp.debugfrom the environment, merges registered executableConfigFilemodules, then runs yourconfigurecallbacks. - Your configuration. Any
.configure { ... }callbacks you added run next, so they can override defaults and file values. - Register phase. Each provider’s
registermethod runs, in the order you listed them. Providers only describe services here. - Boot phase. After every provider has registered, each provider’s
bootmethod runs. This is where routes are attached and middleware is installed, because everything a provider might need is now bound. - Serving.
KonaHttpServerbinds a Netty socket and hands each incoming request to the HTTP kernel on its own virtual thread. - Per request. The kernel runs global middleware, matches a route (answering
404 Not Foundor405 Method Not Allowedwhen nothing fits), runs route middleware and the handler, and turns exceptions into JSON error responses.
Steps 1 to 5 happen once. Step 7 happens for every request.
How these docs are organised
Section titled “How these docs are organised”The sidebar is a progressive path. Read Getting started first, then The basics (routing, controllers, validation, Crema views). When you need internals or background work, open Digging deeper (application, container, grind, events, queues, mail, cache, drip, and more). Branch into Security, Database (Cadence), Frontend (Brew, Inertia, Vite), Testing, and Packages & tooling as your app needs them. The documentation hub mirrors the same groups.
The Kona toolbox
Section titled “The Kona toolbox”Kona is organised into named components. Guides for each live under the sidebar groups above.
| Name | Role | Status |
|---|---|---|
| Kona core | Application, providers, container, config, env, logging (kona-core) |
Available |
| Kona HTTP | Router, middleware, HTTP kernel, validation, embedded server (kona-http) |
Available |
| kona | Global CLI: kona new (kona-cli) |
Available |
| grind | App-local CLI: ./grind serve, make:*, migrate, db:seed (kona-grind) |
Available |
| steam | Interactive shell inside a booted application (kona-steam) |
Available |
| Cadence | Database connections, query builder, models, relations, migrations, seeders, factories (kona-cadence) — see Cadence |
Available |
| Crema | Server-side HTML templates (kona-crema) — see Crema |
Available |
| drip | Outbound HTTP client (kona-drip) — see drip |
Available |
Design choices worth knowing up front
Section titled “Design choices worth knowing up front”- JDK 21 or newer. The embedded server runs each request on a virtual thread: a lightweight thread managed by the JVM. Handlers are plain blocking code; you do not need callbacks or coroutines to serve many concurrent requests.
- Compose, don’t embed. Kona is built from scratch on focused libraries (Netty for HTTP, Jackson for JSON, SLF4J for logging). There is no larger framework running underneath it.
- Explicit wiring. Services are bound in providers you can read. There is no classpath scanning: if a route exists, some provider or bootstrap code registered it.
- Kotlin-first, Java first-class. Every public API has a natural Java call site, and every guide shows both languages. The Kotlin and Java page covers the few places where the syntax differs.
Where to go next
Section titled “Where to go next”- Installation: install global
kona, then create an app. - Your first app:
kona new, then./grind serve. - Kotlin and Java: how the same APIs look from each language.
- Routing: the first page in The basics — map URLs to handlers.
- Application & providers: later, under Digging deeper, the boot sequence in depth.