Skip to content
Brew

Installation

Brew ships as org.konaframework:kona-brew. Add it next to your other Kona dependencies:

dependencies {
implementation("org.konaframework:kona-http:0.1.0-SNAPSHOT")
implementation("org.konaframework:kona-session:0.1.0-SNAPSHOT")
implementation("org.konaframework:kona-crema:0.1.0-SNAPSHOT")
implementation("org.konaframework:kona-brew:0.1.0-SNAPSHOT")
}

Until Central publishes are live, publish both repos to Maven local:

Terminal window
# From a Kona checkout
./gradlew publishToMavenLocal -x test
# From a kona-brew checkout
./gradlew :kona-brew:publishToMavenLocal

Or scaffold with the brew starter kit (when available on your Kona CLI):

Terminal window
kona new my-app --kit=brew

Register HTTP, session, Crema, and Brew. Session + CSRF matter because update requests carry _token.

Kona.create(args)
.configure {
it.set("app.key", Env.getOrDefault("APP_KEY", "change-me"))
it.set("session.driver", "cookie")
}
.providers(
HttpServiceProvider(),
SessionServiceProvider(),
CremaServiceProvider(),
BrewServiceProvider(),
)
.afterBoot { app ->
HttpMiddleware()
.alias("start.session") { StartSession(app.resolve(SessionManager::class.java)) }
.alias("csrf") { VerifyCsrfToken() }
.web(listOf("start.session", "csrf"))
.apply(app)
}
.boot()

BrewServiceProvider binds BrewManager, discovers components under app.brew by default, and registers:

Method Path Purpose
POST /brew/update Apply property updates + action calls; return new snapshots and HTML
GET /brew/brew.js Readable client bundle
GET /brew/brew.min.js Minified bundle (+ .map)
GET /brew/brew.csp.min.js CSP-oriented bundle when configured

When brew.inject_assets is true (default), Brew injects styles and the script tag into full HTML responses that do not already include @brewScripts.

For layouts you control explicitly:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>@yield('title', 'App')</title>
@brewStyles
</head>
<body>
@yield('content')
@brewScripts
</body>
</html>

@brewScripts emits the CSRF-aware script tag that loads Alpine + Brew and calls Brew.start() on DOMContentLoaded (unless you set window.brewScriptConfig for a custom ESM bundle).

After Brew is registered, app-local grind picks up Brew commands:

Terminal window
./grind make:brew counter
./grind make:brew todos --class
./grind make:brew counter --lang=java --test
./grind brew:publish
./grind brew:stubs
./grind brew:layout
./grind brew:convert path/to/Component.kt

See grind commands for details.

Key Default Role
app.key — HMAC key for snapshot checksums
brew.class_namespace app.brew Package roots for <brew:name /> resolution
brew.path /brew Base path for update + script routes
brew.view_prefix brew Convention view prefix (views/brew/<name>.crema.html)
brew.inject_assets true Auto-inject styles/scripts into HTML responses
brew.inject_morph_markers true Wrap loops/conditionals for keyed morph
brew.csrf true Require CSRF token on updates when a session exists
brew.payload.max_size 1_048_576 Max request body bytes (0 disables)
brew.payload.max_components 20 Max components per update
brew.payload.max_calls 50 Max method calls per component
brew.payload.max_nesting_depth 10 Max dot-path depth for wire:model updates

Custom routes:

Brew.setUpdateRoute("/custom/brew/update")
Brew.setScriptRoute("/custom/brew/script.js")
  1. Create a counter with ./grind make:brew counter.
  2. Embed <brew:counter /> in a Crema page.
  3. Open the page, click the button, and confirm the count updates without a full reload.
  4. In DevTools, confirm window.Brew and window.Alpine exist.