A fresh wind
for your data layer.

Task-focused tutorials for engineers coming from JPA, Hibernate, or Exposed, plus how-to recipes for Storm itself. Each comparison takes a persistence task you already know, shows both approaches side by side, and lets you inspect the SQL they produce.

//From JPAYou know Spring Data JPA and Hibernate. Each tutorial shows a task the JPA way and the Storm way, side by side.
Solving the N+1 problem
Why JPA list queries degrade into 1 + N selects, what JOIN FETCH and entity graphs actually fix, and how Storm removes the problem by making loading policy part of the entity model.
JPA to Storm7 min readKotlin
Projections: read-only views on your data
JPA entities are read-write, and @Immutable is a runtime convention. A Storm projection models a read-only view on the data, a table subset or a database view, built to be nested, filtered, and reused.
JPA to Storm6 min readKotlin
Typed query results without the mapping layer
JPA shapes custom results with proxies and constructor expressions that resolve at runtime. In Storm, any data class is a result type: define it next to the query and rows map by position.
JPA to Storm5 min readKotlin
Pagination and keyset scrolling
Offset pages scan deeper as users page further, and every request pays for a count. Storm offers classic pages when the UI needs them and cursor-based scrolling with REST-ready cursors when it does not.
JPA to Storm6 min readKotlin
Upserts without the workarounds
JPA's find-then-save pattern is two statements and one race condition. Storm generates the database's native upsert syntax: atomic, batched, and portable across all major databases.
JPA to Storm5 min readKotlin
Optimistic locking with immutable entities
JPA checks the version at flush time, far from the code that made the change. Storm checks it on the update statement itself, and immutable values make conflict handling ordinary code.
JPA to Storm5 min readKotlin
Transactions without the proxy rules
@Transactional works through proxies, with rules around self-invocation and visibility that fail silently. Storm's transaction blocks make the scope visible, add onCommit callbacks, and stay coroutine-aware.
JPA to Storm6 min readKotlin
Mapped collections vs queried associations
owner.pets is one property access, and that is genuinely convenient. Storm queries the association instead: one line that loads when you decide, composes with filters and paging, and survives the join table growing columns.
JPA to Storm6 min readKotlin
Full SQL without giving up safety
Native queries return untyped rows and invite concatenation. Storm's SQL templates bind interpolated values safely, map rows to data classes, and expand your entities into columns and joins.
JPA to Storm6 min readKotlin
//From ExposedYou know and like JetBrains Exposed, with good reason. Same format: the Exposed way next to the Storm way.
One model instead of three
Exposed earned its reputation, and on type safety the two are equals. The difference is where knowledge lives: joins and mappings travel with every query, while Storm declares the model once, which compounds on large schemas.
Exposed to Storm6 min readKotlin
Ktor services, side by side
Home ground for both. Exposed connects a Database and wraps every route operation in a transaction; Storm installs as a plugin, reads without ceremony, and its suspend transactions ride the coroutine context.
Exposed to Storm5 min readKotlin
Eager loading and N+1
Exposed's .with() batches references efficiently, one call site at a time, a step above the SQL it runs. Storm puts loading policy in the model, so there is nothing to remember and nothing to forget.
Exposed to Storm5 min readKotlin
Transactions translate almost one to one
Exposed and Storm agree that transactions are explicit blocks. A translation table for the settings you know, plus the places they differ: propagation per block, onCommit callbacks, and built-in retry on the Exposed side.
Exposed to Storm5 min readKotlin
Queries and full SQL
The everyday queries translate almost line by line. The gap opens past the DSL: exec() hands you a raw ResultSet, while Storm's SQL templates keep typed rows and bind-safe parameters.
Exposed to Storm5 min readKotlin
Upserts and batching
Both libraries generate native, dialect-aware upserts, so this is mostly a translation guide. Exposed offers finer control over the update branch; Storm works at the entity level and returns hydrated values.
Exposed to Storm4 min readKotlin
Who owns the schema
Exposed generates DDL from table objects, excellent early on. Storm is schema-first: migrations own the schema and validateSchema() catches drift at startup or in CI. A winner on each side.
Exposed to Storm4 min readKotlin
//The Storm wayAlready using Storm? Task recipes, no comparisons, straight to the point.
In progress
Converters and custom types Composite and natural keys Entity caching and dirty checking

Want one of these sooner, or a topic that is not listed? Open an issue on GitHub.