
Type-safe ORM with expressive SQL DSL, typed predicates, catalog-scoped tables, transactions, joins and aggregations, migrations, reactive query flows, and Ktor-friendly server integration.
Type-safe ORM and SQL DSL for Kotlin Multiplatform.
Kormium gives you an Exposed-like Kotlin API for tables, entities, typed predicates, transactions, migrations, joins and aggregations, with one schema and query model shared across server and client. The core runs on JVM, Kotlin/Native, Android and iOS — and, experimentally, on Node and in the browser (Wasm). It ships PostgreSQL, MySQL/MariaDB and SQLite backends, async r2dbc (PostgreSQL and MySQL) and Ktor integration modules.
object App : Catalog
object Users : Table<App, User>("users", ::User) {
val id by Column.UUID().primaryKey()
val name by Column.Text()
val age by Column.Int()
}
class User : Entity() {
var id by Users.id
var name by Users.name
var age by Users.age
}
val db: Database<App> = createDatabase(
host = "localhost",
database = "postgres",
user = "postgres",
password = "password",
)
val adults = db.autocommit {
Users.find {
where { Users.age gtEq 18 }
orderBy DESC Users.age
limit = 50
}
}Users.age gtEq 18), and values are always bound as parameters.Table<App, User> cannot be used inside a Database<Cache>
scope, and the compiler catches that before runtime.transaction { } and
autocommit { }; suspend code uses suspendTransaction { } and
suspendAutocommit { }.kormium-observe turns a query into a Flow that re-emits when the
tables it reads change — for Compose Multiplatform and Android UIs.Kormium is designed to be cheap and correct to write with a coding agent, not just by hand.
'18' instead of 18,
a type that doesn't match — fail at compile time, inside the generate→compile→fix loop the
agent already runs.find / insert / insertAll / update / deleteWhere
read like the SQL they emit, and the Exposed-style DSL is close to forms models already know.AGENTS.md is a canonical, copy-ready
snippet reference, and llms.txt indexes the docs for ingestion — point your
agent at them so it leads with the idiomatic path instead of low-level escape hatches.Pre-1.0 — stable core. The core API is ~90% frozen and covered by tests. Kormium follows strict Semantic Versioning: any breaking change before 1.0 is called out explicitly in CHANGELOG.md with a migration path. You get predictable upgrades, not surprise rewrites.
Requires JDK 21+ for JVM builds. The JVM suspend offload path uses virtual threads.
Every backend is exercised against a real database, never a mock or an in-memory fake standing in for the production engine. The same suite runs across the platform matrix so a green build means "works on every supported target", not just on the JVM.
Integration & end-to-end, on real engines. On the JVM, the async (r2dbc), JDBC MySQL and Ktor/Koin/sample backends spin up ephemeral PostgreSQL and MySQL instances per run via Testcontainers, so tests own their database lifecycle and leave nothing behind. SQLite is tested against a genuine SQLite library (in-memory) on every target.
Kotlin/Native, against live servers. Testcontainers is a JVM library, so the
native path takes a different route: the linuxX64 and mingwX64 test
executables link the real libpq / libsqlite3 / libmariadb and connect to a
PostgreSQL 16 and MariaDB 11 server provisioned by CI (service containers
on Linux, the preinstalled PostgreSQL service on Windows). The native drivers are
validated end-to-end, not just compiled.
Platform matrix (CI).
| Target | Where it runs | What's verified |
|---|---|---|
| JVM (JDK 21) | Linux + Windows | Unit + integration; both the blocking and the suspend/offload paths |
Native linuxX64
|
Linux | Native tests against live Postgres, MySQL, SQLite |
Native mingwX64 (Windows) |
Windows | Native tests against a live Postgres + in-memory SQLite |
Android + iOS (iosArm64/iosX64/iosSimulatorArm64) |
macOS | Klibs cross-compiled for every Compose-Multiplatform module |
Test reports are uploaded as CI artifacts on every run.
Kormium is published to Maven Central under io.github.kormium.
dependencies {
implementation(platform("io.github.kormium:kormium-bom:<version>"))
implementation("io.github.kormium:kormium-postgres") // PostgreSQL, JVM + Native
// implementation("io.github.kormium:kormium-mysql") // MySQL / MariaDB, JVM + Native
// implementation("io.github.kormium:kormium-sqlite") // SQLite, JVM + Native + Android
// implementation("io.github.kormium:kormium-r2dbc") // async PostgreSQL + MySQL, JVM only
// Experimental (new in 0.9.0): kormium-sqlite-wasm (browser), kormium-{sqlite,postgres,mysql}-node — see docs/web-targets.md
// implementation("io.github.kormium:kormium-observe") // reactive Flow queries
// implementation("io.github.kormium:kormium-migrate") // SQL migration runner
// optional Ktor integration
// implementation("io.github.kormium:kormium-ktor")
// implementation("io.github.kormium:kormium-ktor-di")
// implementation("io.github.kormium:kormium-ktor-koin")
}See Installation for Gradle variants, native system libraries and module details.
| Platform | PostgreSQL | MySQL / MariaDB | SQLite | Notes |
|---|---|---|---|---|
| JVM | JDBC/HikariCP; async r2dbc | JDBC; async r2dbc | sqlite-jdbc | The most stable server target |
| Linux Native | libpq | libmariadb | sqlite3 | Covered by CI native tests |
| macOS Native | libpq | libmariadb | sqlite3 | Published artifacts for x64 and arm64 |
| Windows Native | libpq (experimental) | JVM driver only | sqlite3 (experimental) | CI runs JVM + native tests on a Windows runner |
| Android | Not shipped | Not shipped | AndroidX SQLite | Client target; kormium-core + kormium-sqlite compile for Android |
| iOS | Not shipped | Not shipped | sqlite3 | Client target; core, kormium-sqlite and Ktor integration compile for iOS |
| Node (experimental) | node-postgres | mysql2 | better-sqlite3 | New in 0.9.0 |
| Browser / Wasm (experimental) | — | — | wa-sqlite | New in 0.9.0; runs in the browser |
Note: the web targets — Node and browser/Wasm — are experimental and new in 0.9.0. The rest of the matrix is exercised by CI against real databases (see Testing strategy).
Kormium does not own schema management — create tables with raw SQL or a migration tool.
db.transaction {
executeUpdate(
"""CREATE TABLE IF NOT EXISTS "users" ("id" uuid NOT NULL, "name" text NOT NULL, "age" integer NOT NULL, PRIMARY KEY ("id"))""",
)
Users.insert(User().apply {
id = Uuid.random()
name = "Ada"
age = 36
})
}
val ada = db.autocommit {
Users.find {
where { Users.name like "A%" }
where { Users.age gtEq 18 }
}
}For deeper examples, start with Quick start and then read Queries.
Runnable samples live under samples/:
| Sample | Shows |
|---|---|
samples:crud-sqlite |
Standalone SQLite CRUD and migrations |
samples:sharding |
Catalog safety and multiple database instances |
samples:sqlite-cache |
SQLite cache in front of PostgreSQL |
samples:cross-instance-cache |
Cross-instance cache invalidation over Redis (rethis) |
samples:ktor-di |
Ktor CRUD with built-in DI |
samples:ktor-koin |
Ktor CRUD with Koin |
samples:r2dbc |
Ktor CRUD on async r2dbc PostgreSQL |
samples:wasm-todo |
SQLite in the browser: Compose Multiplatform + wa-sqlite (experimental) |
Type-safe ORM and SQL DSL for Kotlin Multiplatform.
Kormium gives you an Exposed-like Kotlin API for tables, entities, typed predicates, transactions, migrations, joins and aggregations, with one schema and query model shared across server and client. The core runs on JVM, Kotlin/Native, Android and iOS — and, experimentally, on Node and in the browser (Wasm). It ships PostgreSQL, MySQL/MariaDB and SQLite backends, async r2dbc (PostgreSQL and MySQL) and Ktor integration modules.
object App : Catalog
object Users : Table<App, User>("users", ::User) {
val id by Column.UUID().primaryKey()
val name by Column.Text()
val age by Column.Int()
}
class User : Entity() {
var id by Users.id
var name by Users.name
var age by Users.age
}
val db: Database<App> = createDatabase(
host = "localhost",
database = "postgres",
user = "postgres",
password = "password",
)
val adults = db.autocommit {
Users.find {
where { Users.age gtEq 18 }
orderBy DESC Users.age
limit = 50
}
}Users.age gtEq 18), and values are always bound as parameters.Table<App, User> cannot be used inside a Database<Cache>
scope, and the compiler catches that before runtime.transaction { } and
autocommit { }; suspend code uses suspendTransaction { } and
suspendAutocommit { }.kormium-observe turns a query into a Flow that re-emits when the
tables it reads change — for Compose Multiplatform and Android UIs.Kormium is designed to be cheap and correct to write with a coding agent, not just by hand.
'18' instead of 18,
a type that doesn't match — fail at compile time, inside the generate→compile→fix loop the
agent already runs.find / insert / insertAll / update / deleteWhere
read like the SQL they emit, and the Exposed-style DSL is close to forms models already know.AGENTS.md is a canonical, copy-ready
snippet reference, and llms.txt indexes the docs for ingestion — point your
agent at them so it leads with the idiomatic path instead of low-level escape hatches.Pre-1.0 — stable core. The core API is ~90% frozen and covered by tests. Kormium follows strict Semantic Versioning: any breaking change before 1.0 is called out explicitly in CHANGELOG.md with a migration path. You get predictable upgrades, not surprise rewrites.
Requires JDK 21+ for JVM builds. The JVM suspend offload path uses virtual threads.
Every backend is exercised against a real database, never a mock or an in-memory fake standing in for the production engine. The same suite runs across the platform matrix so a green build means "works on every supported target", not just on the JVM.
Integration & end-to-end, on real engines. On the JVM, the async (r2dbc), JDBC MySQL and Ktor/Koin/sample backends spin up ephemeral PostgreSQL and MySQL instances per run via Testcontainers, so tests own their database lifecycle and leave nothing behind. SQLite is tested against a genuine SQLite library (in-memory) on every target.
Kotlin/Native, against live servers. Testcontainers is a JVM library, so the
native path takes a different route: the linuxX64 and mingwX64 test
executables link the real libpq / libsqlite3 / libmariadb and connect to a
PostgreSQL 16 and MariaDB 11 server provisioned by CI (service containers
on Linux, the preinstalled PostgreSQL service on Windows). The native drivers are
validated end-to-end, not just compiled.
Platform matrix (CI).
| Target | Where it runs | What's verified |
|---|---|---|
| JVM (JDK 21) | Linux + Windows | Unit + integration; both the blocking and the suspend/offload paths |
Native linuxX64
|
Linux | Native tests against live Postgres, MySQL, SQLite |
Native mingwX64 (Windows) |
Windows | Native tests against a live Postgres + in-memory SQLite |
Android + iOS (iosArm64/iosX64/iosSimulatorArm64) |
macOS | Klibs cross-compiled for every Compose-Multiplatform module |
Test reports are uploaded as CI artifacts on every run.
Kormium is published to Maven Central under io.github.kormium.
dependencies {
implementation(platform("io.github.kormium:kormium-bom:<version>"))
implementation("io.github.kormium:kormium-postgres") // PostgreSQL, JVM + Native
// implementation("io.github.kormium:kormium-mysql") // MySQL / MariaDB, JVM + Native
// implementation("io.github.kormium:kormium-sqlite") // SQLite, JVM + Native + Android
// implementation("io.github.kormium:kormium-r2dbc") // async PostgreSQL + MySQL, JVM only
// Experimental (new in 0.9.0): kormium-sqlite-wasm (browser), kormium-{sqlite,postgres,mysql}-node — see docs/web-targets.md
// implementation("io.github.kormium:kormium-observe") // reactive Flow queries
// implementation("io.github.kormium:kormium-migrate") // SQL migration runner
// optional Ktor integration
// implementation("io.github.kormium:kormium-ktor")
// implementation("io.github.kormium:kormium-ktor-di")
// implementation("io.github.kormium:kormium-ktor-koin")
}See Installation for Gradle variants, native system libraries and module details.
| Platform | PostgreSQL | MySQL / MariaDB | SQLite | Notes |
|---|---|---|---|---|
| JVM | JDBC/HikariCP; async r2dbc | JDBC; async r2dbc | sqlite-jdbc | The most stable server target |
| Linux Native | libpq | libmariadb | sqlite3 | Covered by CI native tests |
| macOS Native | libpq | libmariadb | sqlite3 | Published artifacts for x64 and arm64 |
| Windows Native | libpq (experimental) | JVM driver only | sqlite3 (experimental) | CI runs JVM + native tests on a Windows runner |
| Android | Not shipped | Not shipped | AndroidX SQLite | Client target; kormium-core + kormium-sqlite compile for Android |
| iOS | Not shipped | Not shipped | sqlite3 | Client target; core, kormium-sqlite and Ktor integration compile for iOS |
| Node (experimental) | node-postgres | mysql2 | better-sqlite3 | New in 0.9.0 |
| Browser / Wasm (experimental) | — | — | wa-sqlite | New in 0.9.0; runs in the browser |
Note: the web targets — Node and browser/Wasm — are experimental and new in 0.9.0. The rest of the matrix is exercised by CI against real databases (see Testing strategy).
Kormium does not own schema management — create tables with raw SQL or a migration tool.
db.transaction {
executeUpdate(
"""CREATE TABLE IF NOT EXISTS "users" ("id" uuid NOT NULL, "name" text NOT NULL, "age" integer NOT NULL, PRIMARY KEY ("id"))""",
)
Users.insert(User().apply {
id = Uuid.random()
name = "Ada"
age = 36
})
}
val ada = db.autocommit {
Users.find {
where { Users.name like "A%" }
where { Users.age gtEq 18 }
}
}For deeper examples, start with Quick start and then read Queries.
Runnable samples live under samples/:
| Sample | Shows |
|---|---|
samples:crud-sqlite |
Standalone SQLite CRUD and migrations |
samples:sharding |
Catalog safety and multiple database instances |
samples:sqlite-cache |
SQLite cache in front of PostgreSQL |
samples:cross-instance-cache |
Cross-instance cache invalidation over Redis (rethis) |
samples:ktor-di |
Ktor CRUD with built-in DI |
samples:ktor-koin |
Ktor CRUD with Koin |
samples:r2dbc |
Ktor CRUD on async r2dbc PostgreSQL |
samples:wasm-todo |
SQLite in the browser: Compose Multiplatform + wa-sqlite (experimental) |