Skip to content
Kona

Your first app

  • JDK 21+
  • Global kona on your PATH (Installation — curl …/scripts/install.sh | bash)
Terminal window
kona new hello-kona
cd hello-kona

Use --lang=java for a Java skeleton. The default kit is web (Crema welcome view). Other kits: --kit=api, --kit=inertia, --kit=brew. kona new refuses to overwrite an existing directory.

You should see something like:

Created Kona application at …/hello-kona (kotlin, kit=web)
cd hello-kona
./grind serve
# or: kona grind serve

That ./grind file is part of the scaffold. kona grind … is a global convenience that finds this file for you. If you opened samples/hello-* in the Kona git checkout instead, you will not find ./grind there — those are monorepo modules; see Installation → Trying the repo samples.

Everything application-owned lives under src/main (plus project-root storage/ and .env):

Path Role
./grind / grind.bat App-local CLI (serve, make:controller, …) — written by kona new
./gradlew / gradlew.bat Gradle wrapper — builds and runs the app
.env / .env.example APP_NAME, APP_KEY (generated), APP_DEBUG, HOST, PORT, …
src/main/kotlin/bootstrap/App (or …/java/…) Boots Kona, registers providers, starts HTTP
src/main/…/bootstrap/Middleware Session + CSRF (/api/* excepted); trust proxies/hosts
src/main/…/app/providers/ Your service provider
src/main/…/app/http/controllers/ Controllers
src/main/…/routes/WebRoutes + ApiRoutes Web and /api route tables
src/main/resources/config/ JSON config (app, http, paths, session)
src/main/resources/views/ Crema views (welcome.crema.html on the web kit)
src/main/resources/public/ Public static files
storage/ Writable runtime data (logs, framework cache)
build.gradle.kts HTTP, grind, extract, redis, session, auth, queue, schedule, mail, crema

kona itself is not copied into the project. Only ./grind (plus the Gradle wrapper and app sources) is local.

After boot, resolve directories with Application helpers or the Paths facade:

app.appPath("http", "controllers")
app.storagePath("logs")
app.configPath()
Paths.view("welcome")
Paths.publicDir()

Defaults follow the tree above; override with paths.* keys in config/Paths (registered via .configs(...)).

Terminal window
./grind serve

Open http://127.0.0.1:4000/ (or the HOST/PORT from .env). Stop with Ctrl+C.

Under the hood, ./grind serve runs ./gradlew run so the app compiles with its own dependencies. For tests you can use ./grind serve --in-process after ./gradlew classes.

The default welcome page is HTML from welcome.crema.html (via WelcomeController on /). /api/health returns JSON {"status":"ok"}.

Terminal window
./grind make:controller Post

Then register a route in src/main/…/routes/ that uses it. Generators write under src/main/kotlin|java/app/….

Stay global — do not use grind for this:

Terminal window
cd ..
kona new shop --lang=java
cd shop
./grind serve