Installation
This guide takes you from an empty Kona app (or a brand-new kit) to a working Inertia page: HTML on the first visit, JSON on later visits, with a real Vue / React / Svelte client.
Client adapters, visit options, and form helpers are documented upstream at inertiajs.com. This site documents the Kona server side and how we wire the official clients.
Choose your path
Section titled “Choose your path”| Path | When to use |
|---|---|
| A. Starter kit | Greenfield app — everything scaffolded |
B. ./grind install inertia |
Existing Kona app — dependency + interactive frontend |
| C. Manual | You want every file written by hand |
Paths A and B are the supported “no-brainer” routes. Path C is at the end.
Path A — New app with the inertia kit
Section titled “Path A — New app with the inertia kit”kona new my-app --kit=inertia# Java:kona new my-app --kit=inertia --lang=javacd my-appThe kit includes:
- Maven dependency
org.konaframework:kona-inertia InertiaServiceProvideron the provider list- Config
inertia.root_view=app,inertia.version=1 - Crema root shell
src/main/resources/views/app.crema.html HandleInertiamiddleware pushed after boot- Welcome route that calls
Inertia.render("Pages/Welcome", …) - Vue 3 Vite app (
package.json,vite.config.js,js/app.js,js/Pages/Welcome.vue)
Run it
Section titled “Run it”npm installnpm run dev # terminal 1 — Vite on :5173, writes public/hot./grind serve # terminal 2 — Kona HTTP (default :4000)Open http://127.0.0.1:4000/. You should see the Welcome page. In DevTools → Network, a full document load has no X-Inertia header; after client-side navigation (once you add links), requests include X-Inertia: true and receive JSON.
Until artifacts are on Maven Central for your version line, publish once:
# Kona checkout./gradlew publishToMavenLocal -x test# kona-inertia checkout./gradlew :kona-inertia:publishToMavenLocalGenerated apps resolve org.konaframework from mavenLocal() then Central.
Path B — Add Inertia to an existing app
Section titled “Path B — Add Inertia to an existing app”1. Install the package
Section titled “1. Install the package”From the app root (directory with build.gradle.kts / build.gradle):
./grind install inertia# or from anywhere under the app tree:kona grind install inertiaThat always:
- Adds
implementation("org.konaframework:kona-inertia:…")to Gradle. - Appends
org.konaframework.inertia.InertiaServiceProvidertosrc/main/resources/META-INF/kona/providers.
Then it scaffolds the frontend (interactive when a TTY is available):
Which Inertia frontend stack should we scaffold? [1] Vue 3 (@inertiajs/vue3) [2] React (@inertiajs/react) [3] Svelte (@inertiajs/svelte) [4] Skip — I will wire the client myselfNon-interactive / CI defaults to Vue 3. Override anytime:
./grind install inertia --frontend=vue./grind install inertia --frontend=react./grind install inertia --frontend=svelte./grind install inertia --frontend=none # server package only./grind install inertia --frontend=vue --no-interactive| Flag | Meaning |
|---|---|
--frontend= |
vue, react, svelte, or none |
--no-interactive |
Never prompt; use --frontend or default Vue |
--version= |
Pin the Maven artifact version |
--base= |
App root if grind’s cwd is wrong |
The scaffold writes (when not none):
| File | Role |
|---|---|
package.json |
Vite + official @inertiajs/* adapter |
vite.config.js |
Build to public/build with manifest; dev origin for hot |
src/main/resources/js/app.(js|jsx) |
createInertiaApp entry |
src/main/resources/js/Pages/Welcome.* |
Sample page component |
src/main/resources/views/app.crema.html |
Root HTML shell (only if missing) |
public/.gitkeep |
Public dir for hot + build/ |
Refresh Gradle after install:
./gradlew build# or restart ./grind serve2. Server configuration
Section titled “2. Server configuration”Set these before or while registering providers (kit apps already do):
.configure { cfg -> cfg.set("inertia.root_view", "app") // Crema view name cfg.set("inertia.version", "1") // asset version string // optional: // cfg.set("inertia.public_path", app.basePath.resolve("public").toString()) // cfg.set("inertia.root_html", "<!DOCTYPE html>…") // instead of a Crema view}| Key | Purpose |
|---|---|
inertia.root_view |
Crema view that wraps {!! pageAttr !!} + {!! vite !!} |
inertia.root_html |
Raw HTML string if you do not use Crema |
inertia.version |
Compared on Inertia visits; mismatch → 409 |
inertia.public_path |
Directory containing Vite hot and build/ (default <base>/public) |
Details: Configuration.
React note: the scaffold entry is app.jsx. Point Vite tags at it:
.afterBoot { app -> Inertia.manager().viteEntries = listOf("src/main/resources/js/app.jsx")}(Default viteEntries is src/main/resources/js/app.js, which matches Vue/Svelte.)
3. Register middleware
Section titled “3. Register middleware”InertiaServiceProvider must boot before you push middleware so Inertia.manager() exists.
.afterBoot { application -> application.resolve(HttpKernel::class.java) .pushMiddleware(HandleInertiaRequests()) // or your kit wrapper, e.g. HandleInertia()}.afterBoot(application -> { application.resolve(HttpKernel.class) .pushMiddleware(new HandleInertiaRequests());});Subclass HandleInertiaRequests to share flash/auth props or override version(request). See Middleware.
4. Root template
Section titled “4. Root template”Crema view app (name must match inertia.root_view):
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title inertia>Kona</title> {!! vite !!} </head> <body> <div id="app" data-page="{!! pageAttr !!}"></div> </body></html>{!! vite !!}— script/link tags from the Vite hot file or production manifest (Vite & assets).{!! pageAttr !!}— escaped JSON page object for the first visit.#app— mount element expected by the official adapters.
5. Render a page from a route
Section titled “5. Render a page from a route”router.get("/") { Inertia.render( "Pages/Welcome", mapOf( "title" to "Welcome", "message" to "Inertia is running on Kona", ), )}router.get("/", request -> Inertia.render( "Pages/Welcome", Map.of( "title", "Welcome", "message", "Inertia is running on Kona" ) ));The string "Pages/Welcome" must match a file under js/Pages/ (e.g. Welcome.vue), as resolved by your createInertiaApp resolve function.
6. Frontend install and run
Section titled “6. Frontend install and run”npm installnpm run dev # keep running — creates public/hot./grind serveProduction build (no Vite dev server):
npm run build # writes public/build/manifest.json./grind serve # serves hashed assets via {!! vite !!}7. Verify end-to-end
Section titled “7. Verify end-to-end”- First visit —
GET /withoutX-Inertia→200HTML,#app[data-page]present, Vite client script tags present whenpublic/hotexists. - Inertia visit — same URL with headers:
GET / HTTP/1.1X-Inertia: trueX-Inertia-Version: 1→ 200 JSON { "component", "props", "url", "version" } plus X-Inertia: true.
-
Version mismatch — send
X-Inertia-Version: stalewhile server version is1→409so the client hard-reloads (Asset versioning). -
Browser — Welcome component renders
title/messageprops.
If HTML has an empty body script section, Vite is not running and there is no production manifest yet — start npm run dev or run npm run build.
What “installed” means on the server
Section titled “What “installed” means on the server”| Piece | Role |
|---|---|
kona-inertia artifact |
Facade, manager, middleware, provider |
InertiaServiceProvider |
Binds InertiaManager + Vite AssetManifest |
HandleInertiaRequests |
Per-request share, version check, response headers |
| Root view / HTML | First-visit document shell |
| Config keys | Root view, version, public path |
Package discovery loads providers listed in META-INF/kona/providers when the app boots through grind. See Kona’s Installing packages.
Frontend stacks (official Inertia)
Section titled “Frontend stacks (official Inertia)”Kona does not re-implement the browser protocol. Use the official adapters:
| Stack | Packages | Upstream |
|---|---|---|
| Vue 3 | @inertiajs/vue3, vue, @vitejs/plugin-vue |
Vue setup |
| React | @inertiajs/react, react, react-dom, @vitejs/plugin-react |
React setup |
| Svelte | @inertiajs/svelte, svelte, @sveltejs/vite-plugin-svelte |
Svelte setup |
Deeper client topics (forms, partial reloads, deferred props, when available in your adapter version) live on inertiajs.com. Kona’s job is correct HTML/JSON responses and shared props — see Rendering, Shared data, and Your first page.
Path C — Manual Gradle (optional)
Section titled “Path C — Manual Gradle (optional)”dependencies { implementation("org.konaframework:kona-http:0.1.0") implementation("org.konaframework:kona-crema:0.1.0") implementation("org.konaframework:kona-inertia:0.1.0")}Register InertiaServiceProvider, push middleware, add the root view, then either run ./grind install inertia --frontend=vue (reuses scaffold without failing if the dependency exists) or copy the Vite files from Path B’s table by hand.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause |
|---|---|
InertiaException / no manager |
Provider not registered or middleware before boot |
Empty {!! vite !!} |
No public/hot and no public/build/manifest.json |
| Blank page, console error “page not found” | Component name ≠ file under js/Pages/ |
| Always full HTML on XHR | Missing HandleInertiaRequests or client not sending X-Inertia |
Persistent 409 |
Client X-Inertia-Version ≠ server inertia.version |
| React assets 404 | viteEntries still pointing at app.js instead of app.jsx |
- Your first page — request/response walkthrough
- Frontend clients — how the scaffolded apps mount
- Rendering pages —
Inertia.renderAPI - Starter kit — kit file map
- inertiajs.com — client protocol and adapters