
Flexible ORM simplifying database CRUD on plain classes with annotation-free mapping, lazy loading, coroutine-based transactions, paginated queries, stored-procedure support, composite-key handling, and native driver access.
Stormify is a flexible ORM library for Kotlin Multiplatform that simplifies database interactions with minimal configuration. It operates and performs CRUD operations on plain Kotlin classes without requiring extensive annotations or XML setups, as long as field names match database columns.
Designed for developers seeking a simple yet powerful ORM, Stormify excels in projects that favor convention over configuration, allowing for minimal setup and clean, straightforward code.
IN clauses.by db() delegates for automatic lazy loading of related entities.PagedList<T> for UI grids (ZK/Compose/Swing) and PagedQuery<T> for stateless REST endpoints — filters, sorting, FK traversal, aggregations, facet counts, and streaming iteration over very large result sets.<dependency>
<groupId>onl.ycode</groupId>
<artifactId>stormify-jvm</artifactId>
<version>2.1.1</version>
</dependency>implementation("onl.ycode:stormify-jvm:2.1.1")
ksp("onl.ycode:annproc:2.1.1") // optional on JVMimplementation("onl.ycode:stormify-android:2.1.1")
ksp("onl.ycode:annproc:2.1.1") // required on Android// Pick the artifact for your target platform:
implementation("onl.ycode:stormify-linuxx64:2.1.1") // Linux x64
implementation("onl.ycode:stormify-linuxarm64:2.1.1") // Linux ARM64
implementation("onl.ycode:stormify-mingwx64:2.1.1") // Windows x64
implementation("onl.ycode:stormify-macosarm64:2.1.1") // macOS (Apple Silicon)
implementation("onl.ycode:stormify-macosx64:2.1.1") // macOS (Intel)
implementation("onl.ycode:stormify-iosarm64:2.1.1") // iOS (device)
implementation("onl.ycode:stormify-iossimulatorarm64:2.1.1") // iOS simulator (Apple Silicon)
implementation("onl.ycode:stormify-iosx64:2.1.1") // iOS simulator (Intel Mac)
ksp("onl.ycode:annproc:2.1.1") // required (no reflection on native)Supported native databases: PostgreSQL, MariaDB/MySQL, Oracle, MSSQL, SQLite. On iOS, only SQLite is available.
Entity metadata: On JVM, entity metadata is discovered at runtime via kotlin-reflect
(included as a transitive dependency). On Native/Android/iOS, use the annproc annotation
processor (via KSP) to generate it at compile time. On JVM, annproc is optional but
improves startup time and allows excluding kotlin-reflect. When using annproc, pass
the generated registrar to the constructor:
val stormify = Stormify(dataSource, GeneratedEntities)Upgrading from V1? See the V1 to V2 migration guide.
Stormify works with any JDBC DataSource. The examples below use HikariCP, but any connection pool or plain driver will work.
Kotlin (JVM):
val config = HikariConfig("databaseConfig.properties")
val dataSource = HikariDataSource(config)
val stormify = Stormify(dataSource)Java:
HikariConfig config = new HikariConfig("databaseConfig.properties");
HikariDataSource dataSource = new HikariDataSource(config);
StormifyJ stormify = new StormifyJ(dataSource);Android:
val db = context.openOrCreateDatabase("mydb.db", Context.MODE_PRIVATE, null)
val stormify = Stormify(db)Native:
val ds = KdbcDataSource("jdbc:postgresql://localhost:5432/mydb", "user", "pass")
val stormify = Stormify(ds)Define a simple Kotlin class. The library automatically maps fields based on their names.
For a table CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(255)):
@DbTable("test") // optional on JVM — class name is used by default
data class Test(
@DbField(primaryKey = true)
var id: Int = 0,
var name: String = ""
)Mark primary keys with @DbField(primaryKey = true), or register a primary key resolver to detect them by naming convention.
// Create
val record = stormify.create(Test(id = 1, name = "Test Entry"))
// Read
val results = stormify.read<Test>("SELECT * FROM test")
// Update
record.name = "Updated Entry"
stormify.update(record)
// Delete
stormify.delete(record)Kotlin:
stormify.transaction {
val user = create(User(email = "test@example.com"))
create(Profile(userId = user.id, name = "Test User"))
update(account)
}Java:
stormify.transaction(tx -> {
User user = tx.create(new User("test@example.com"));
tx.create(new Profile(user.getId(), "Test User"));
tx.update(account);
});// Query with parameters
val users = stormify.read<User>("SELECT * FROM users WHERE age > ?", 25)
// Single result
val user = stormify.readOne<User>("SELECT * FROM users WHERE id = ?", 1)
// Find by ID
val user = stormify.findById<User>(1)Runnable example projects live in a separate repository: stormify-examples. They cover JVM (Kotlin & Java), Android, iOS, Kotlin/Native (Linux, Windows, macOS), and Kotlin Multiplatform.
Clone them standalone:
git clone -b 2.1.1 https://github.com/teras/stormify-examples.gitOr pull them directly inside this repo as a submodule:
git submodule update --init --recursiveEach subfolder is a self-contained project with its own README.md explaining how to build and run it. See the Examples overview for a short description of each.
A quick side-by-side against common Kotlin and Java ORMs. See the full comparison for reflection behaviour, compile-time metadata, narrative context, and when to pick each.
| Stormify | Exposed | Ktorm | Komapper | SQLDelight | Hibernate | |
|---|---|---|---|---|---|---|
| Multiplatform · JVM + Android + native + iOS | ✓ | JVM + Android | JVM | JVM | ✓ | JVM |
| Native DB drivers · no JDBC required | ✓ | — | — | — | SQLite only | — |
| Facet-aware paged queries, built-in | ✓ | — | — | — | — | — |
| Any class as entity | ✓ | — | — | — | — | — |
| Accepts JPA annotations | ✓ | — | — | — | — | ✓ |
| Suspend / coroutines API | ✓ | ✓ | — | ✓ | ✓ | — |
| Lazy reference delegates | ✓ | DAO only | eager only | — | — | ✓ |
| Stored procedures (in/out/inout) | ✓ | manual | manual | — | — | ✓ |
Full documentation is available at stormify.org/docs.
Contributions are welcome! Please check the Contributing guide for instructions on how to get involved, report issues, or submit pull requests.
Stormify is licensed under the Apache License 2.0. You are free to use, modify, and distribute this library in accordance with the terms of the license.
Enjoy using Stormify? Please star this repository to show your support!
Stormify is a flexible ORM library for Kotlin Multiplatform that simplifies database interactions with minimal configuration. It operates and performs CRUD operations on plain Kotlin classes without requiring extensive annotations or XML setups, as long as field names match database columns.
Designed for developers seeking a simple yet powerful ORM, Stormify excels in projects that favor convention over configuration, allowing for minimal setup and clean, straightforward code.
IN clauses.by db() delegates for automatic lazy loading of related entities.PagedList<T> for UI grids (ZK/Compose/Swing) and PagedQuery<T> for stateless REST endpoints — filters, sorting, FK traversal, aggregations, facet counts, and streaming iteration over very large result sets.<dependency>
<groupId>onl.ycode</groupId>
<artifactId>stormify-jvm</artifactId>
<version>2.1.1</version>
</dependency>implementation("onl.ycode:stormify-jvm:2.1.1")
ksp("onl.ycode:annproc:2.1.1") // optional on JVMimplementation("onl.ycode:stormify-android:2.1.1")
ksp("onl.ycode:annproc:2.1.1") // required on Android// Pick the artifact for your target platform:
implementation("onl.ycode:stormify-linuxx64:2.1.1") // Linux x64
implementation("onl.ycode:stormify-linuxarm64:2.1.1") // Linux ARM64
implementation("onl.ycode:stormify-mingwx64:2.1.1") // Windows x64
implementation("onl.ycode:stormify-macosarm64:2.1.1") // macOS (Apple Silicon)
implementation("onl.ycode:stormify-macosx64:2.1.1") // macOS (Intel)
implementation("onl.ycode:stormify-iosarm64:2.1.1") // iOS (device)
implementation("onl.ycode:stormify-iossimulatorarm64:2.1.1") // iOS simulator (Apple Silicon)
implementation("onl.ycode:stormify-iosx64:2.1.1") // iOS simulator (Intel Mac)
ksp("onl.ycode:annproc:2.1.1") // required (no reflection on native)Supported native databases: PostgreSQL, MariaDB/MySQL, Oracle, MSSQL, SQLite. On iOS, only SQLite is available.
Entity metadata: On JVM, entity metadata is discovered at runtime via kotlin-reflect
(included as a transitive dependency). On Native/Android/iOS, use the annproc annotation
processor (via KSP) to generate it at compile time. On JVM, annproc is optional but
improves startup time and allows excluding kotlin-reflect. When using annproc, pass
the generated registrar to the constructor:
val stormify = Stormify(dataSource, GeneratedEntities)Upgrading from V1? See the V1 to V2 migration guide.
Stormify works with any JDBC DataSource. The examples below use HikariCP, but any connection pool or plain driver will work.
Kotlin (JVM):
val config = HikariConfig("databaseConfig.properties")
val dataSource = HikariDataSource(config)
val stormify = Stormify(dataSource)Java:
HikariConfig config = new HikariConfig("databaseConfig.properties");
HikariDataSource dataSource = new HikariDataSource(config);
StormifyJ stormify = new StormifyJ(dataSource);Android:
val db = context.openOrCreateDatabase("mydb.db", Context.MODE_PRIVATE, null)
val stormify = Stormify(db)Native:
val ds = KdbcDataSource("jdbc:postgresql://localhost:5432/mydb", "user", "pass")
val stormify = Stormify(ds)Define a simple Kotlin class. The library automatically maps fields based on their names.
For a table CREATE TABLE test (id INT PRIMARY KEY, name VARCHAR(255)):
@DbTable("test") // optional on JVM — class name is used by default
data class Test(
@DbField(primaryKey = true)
var id: Int = 0,
var name: String = ""
)Mark primary keys with @DbField(primaryKey = true), or register a primary key resolver to detect them by naming convention.
// Create
val record = stormify.create(Test(id = 1, name = "Test Entry"))
// Read
val results = stormify.read<Test>("SELECT * FROM test")
// Update
record.name = "Updated Entry"
stormify.update(record)
// Delete
stormify.delete(record)Kotlin:
stormify.transaction {
val user = create(User(email = "test@example.com"))
create(Profile(userId = user.id, name = "Test User"))
update(account)
}Java:
stormify.transaction(tx -> {
User user = tx.create(new User("test@example.com"));
tx.create(new Profile(user.getId(), "Test User"));
tx.update(account);
});// Query with parameters
val users = stormify.read<User>("SELECT * FROM users WHERE age > ?", 25)
// Single result
val user = stormify.readOne<User>("SELECT * FROM users WHERE id = ?", 1)
// Find by ID
val user = stormify.findById<User>(1)Runnable example projects live in a separate repository: stormify-examples. They cover JVM (Kotlin & Java), Android, iOS, Kotlin/Native (Linux, Windows, macOS), and Kotlin Multiplatform.
Clone them standalone:
git clone -b 2.1.1 https://github.com/teras/stormify-examples.gitOr pull them directly inside this repo as a submodule:
git submodule update --init --recursiveEach subfolder is a self-contained project with its own README.md explaining how to build and run it. See the Examples overview for a short description of each.
A quick side-by-side against common Kotlin and Java ORMs. See the full comparison for reflection behaviour, compile-time metadata, narrative context, and when to pick each.
| Stormify | Exposed | Ktorm | Komapper | SQLDelight | Hibernate | |
|---|---|---|---|---|---|---|
| Multiplatform · JVM + Android + native + iOS | ✓ | JVM + Android | JVM | JVM | ✓ | JVM |
| Native DB drivers · no JDBC required | ✓ | — | — | — | SQLite only | — |
| Facet-aware paged queries, built-in | ✓ | — | — | — | — | — |
| Any class as entity | ✓ | — | — | — | — | — |
| Accepts JPA annotations | ✓ | — | — | — | — | ✓ |
| Suspend / coroutines API | ✓ | ✓ | — | ✓ | ✓ | — |
| Lazy reference delegates | ✓ | DAO only | eager only | — | — | ✓ |
| Stored procedures (in/out/inout) | ✓ | manual | manual | — | — | ✓ |
Full documentation is available at stormify.org/docs.
Contributions are welcome! Please check the Contributing guide for instructions on how to get involved, report issues, or submit pull requests.
Stormify is licensed under the Apache License 2.0. You are free to use, modify, and distribute this library in accordance with the terms of the license.
Enjoy using Stormify? Please star this repository to show your support!