Skip to content
Kona

Getting started with Crema

Crema is Kona’s server-side view engine. You write templates under src/main/resources/views, pass a data map from a controller, and Crema expands @ directives and {{ }} echoes into HTML. Templates use the extensions *.crema.html or *.crema.kt (plain text with the same directive syntax).

Crema was inspired by familiar server-side template menus; everything after this sentence describes Crema on its own terms.

A view is a named template plus the data used to render it. The name is dotted (home, posts.show) and maps to a file path under the views root (home.crema.html, posts/show.crema.html). After boot, the view helper resolves that name through the app-bound engine and returns a View (or an HTML Response).

Typical request path:

  1. A route hits a controller method.
  2. The controller calls view("welcome", …) (Kotlin) or Views.make("welcome", …) (Java).
  3. Crema loads the template, runs directives, escapes echoes, and returns HTML via toResponse().

kona new (default web kit) already registers CremaServiceProvider and ships a welcome view. Add more templates with grind:

Terminal window
./grind make:view home
./grind make:view posts.show

That creates src/main/resources/views/home.crema.html and src/main/resources/views/posts/show.crema.html.

{{-- src/main/resources/views/home.crema.html --}}
<h1>Hello {{ name }}</h1>

{{ name }} prints the name entry from the data map with HTML escaping. Missing or null values become an empty string.

Register CremaServiceProvider (the web scaffold does this) and boot the app. Then use the view helper:

import org.konaframework.crema.view
import org.konaframework.http.Request
import org.konaframework.http.Response
class WelcomeController {
fun index(request: Request): Response =
view("welcome", mapOf("name" to "Kona")).toResponse()
}

Full factory API (share, first, existence, Java/Kotlin tables): View helper.

Setting Behavior
Default root {basePath}/src/main/resources/views
Fallbacks build/resources/main/views, then legacy resources/views
Override Config key view.path (absolute or app-relative path)

Dotted names become path segments: mail.orders.shipped → mail/orders/shipped.crema.html. Crema tries .crema.html first, then .crema.kt.

Some directives read conventional keys from the same data map (or a child context). You pass them from the controller or middleware:

Key Used by
_token / csrf_token @csrf
asset_url / assetUrl @asset base prefix
__authenticated, auth_user, user @auth / @guest
__abilities or can @can / @cannot
errors @error('field')
lang @lang overrides before Lang.get
Area Directives
Echoes {{ }}, {!! !!}, @@, {{-- --}}
Layouts @extends, @section / @endsection / @show, @yield, @parent, @hasSection, @sectionMissing
Stacks @push / @endpush, @prepend / @endprepend, @stack
Includes @include, @includeIf, @includeWhen, @includeUnless, @includeFirst, @once, @verbatim
Conditionals @if / @elseif / @else / @endif, @unless, @isset, @empty
Loops @while, @foreach / @each / @for, @forelse, loop.*
Auth @auth, @guest, @can, @cannot
Switch @switch / @case / @break / @default / @endswitch
Components @component / @slot, <x-*>, <x-slot>
Helpers @json, @csrf, @method, @asset, @lang, @vite, @error

Full tables: Directive reference.

  • Brew — reactive components that render Crema templates and keep the browser in sync.
  • Inertia — optional root Crema view that hosts a client-side page app.
  • Vite / assets — bundling; Crema’s @vite helper emits thin script/link tags.