Getting started
Kinetica builds with the JetBrains Kotlin Toolchain (the Amper successor): declarative YAML modules, a ./kotlin wrapper CLI, no Gradle.
Project layout
A project is a project.yaml listing modules; a module is a directory with a module.yaml. A minimal browser app (the apply template wires the mandatory compiler plugin — without it every state/event call throws MissingKineticaPluginException at runtime):
# module.yaml
product: js/app
apply:
- ../../common.module-template.yaml # registers io.heapy.kinetica:kinetica-compiler
dependencies:
- ../../kinetica-browser
- ../../kinetica-runtime// src/main.kt
package app
import io.heapy.kinetica.*
import io.heapy.kinetica.browser.mountKineticaApp
@UiComponent
fun ComponentScope.App() {
var name by state { "world" }
column {
textInput(value = name, onInput = event<String> { name = it })
text("Hello, $name!")
}
}
fun main() {
mountKineticaApp("#app") { App() }
}<!-- web/index.html -->
<div id="app"></div>
<script type="module" src="../../../build/artifacts/CompiledWebArtifact/my-appjsrelease/kotlin-output/my-app.mjs"></script>Build and run
./kotlin build -v release -m my-app # links build/artifacts/CompiledWebArtifact/my-appjsrelease/kotlin-output/my-app.mjs
./kotlin test -m my-module # run a module's tests
./kotlin show modules # inspect the project modeljs/app output is an ES-module graph; serve the repository root with any static file server and open the page. JVM apps (product: jvm/app) run with ./kotlin run -m my-server and package to an executable jar with ./kotlin package.
From Gradle
Kinetica is built with the toolchain but consumed from any Kotlin build. For Gradle, the io.heapy.kinetica plugin does the wiring:
// settings.gradle.kts — a fresh project resolves plugins from the portal only
pluginManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
}// build.gradle.kts
plugins {
kotlin("multiplatform") version "2.4.10"
id("io.heapy.kinetica") version "0.4.0"
}
repositories {
mavenCentral()
}
kotlin {
jvm()
js { browser() }
}That is the whole setup. The plugin applies the mandatory compiler plugin to every compilation of every target and adds kinetica-runtime to commonMain — plus kinetica-browser to a JS target's main source set — at its own version. kinetica { addRuntimeDependencies = false } hands the dependencies back to you; everything else the plugin exposes is on the compiler-plugin page.
Kotlin 2.4.10 is the version Kinetica is published with. klib metadata is not forward compatible, so a mismatch fails the compilation — the plugin warns about it before that happens. The plugin itself needs Gradle 8.11+ and a JDK 17+ Kotlin daemon; the compiled application still targets whatever your toolchain says.
Components are plain functions
There is no component class and no special file type. A component is a function with ComponentScope as receiver that emits nodes:
@UiComponent
fun ComponentScope.Badge(label: String) {
host("span", props = mapOf("class" to "badge")) {
text(label)
}
}Composition is a function call: Badge("New"). State lives in slots whose identity the mandatory compiler plugin assigns at compile time — every component is a @UiComponent fun ComponentScope.X(...), and every state/derived/effect call site gets its own slot automatically. Lists still key their rows explicitly: each(items, key = { … }).
Mounting choices
| Entry point | Use for |
|---|---|
mountKineticaApp(selector) { App() } | Browser apps (renderer details) |
KineticaRuntime().render { App() }.tree.toSafeHtml() | Server-side HTML (server components) |
KineticaTest.render { App() } | Headless tests (testing) |
mountKineticaApp defaults to KineticaRuntime(debug = true) — journaling, duplicate-key checks and debug DOM attributes. Pass KineticaRuntime(debug = false) for production mounts.