Skip to main content
Version: 1.9.1

Storm vs Other Frameworks

There is no universally "best" database framework. Each has strengths suited to different situations, team preferences, and project requirements. Teams approach data access differently, including using frameworks at various abstraction levels or even plain SQL. This page provides a comparison to help you evaluate whether Storm fits your needs, particularly if you value explicit and predictable behavior and fast development. We encourage you to explore the linked documentation for each framework and form your own conclusions.

Feature Comparison

The following tables provide a side-by-side comparison of concrete features across all frameworks discussed on this page. "Yes" and "No" indicate built-in support; "Manual" means the feature is achievable but requires explicit effort from the developer.

Entity & Data Modeling

FeatureStormJPASpring DataMyBatisjOOQJDBIExposedKtorm
Lines per entity~5~301~301~20+Generated~15~12~15
Immutable entitiesYesNoNoYesYesYesDSL onlyNo
PolymorphismYes2YesVia JPANoNoNoNoNo
Automatic relationshipsYesYes3Via JPANoNoNoDAO onlyNo
Cascade persistNoYesYesNoNoNoNoNo
Lifecycle callbacksYesYesVia JPANoYesNoDAO onlyNo

1 JPA/Spring Data lines without Lombok; ~10 lines with Lombok.

2 Storm supports Single-Table, Joined Table, and Polymorphic FK strategies using sealed types. JPA additionally supports Table-per-Class and multi-level inheritance hierarchies.

3 JPA relationships are runtime-managed via proxies.

Querying & Data Access

FeatureStormJPASpring DataMyBatisjOOQJDBIExposedKtorm
Type-safe queriesYesCriteriaNoNoYesNoYesYes
SQL TemplatesYesNoNoXML/AnnYesYesNoNo
N+1 preventionYesNoNoNoManualManualNoNo
Lazy loadingRefsYesYesNoNoNoYesYes
Keyset paginationYesNoYesNoYesNoNoNo
JSON columnsYesYes4Via JPAManualYesModuleYesModule
JSON aggregationYesNoNoNoYesNoNoNo

4 JPA requires Hibernate 6.2+ for built-in JSON support; older versions need a third-party library or custom AttributeConverter.

Runtime & Ecosystem

FeatureStormJPASpring DataMyBatisjOOQJDBIExposedKtorm
TransactionsBothBothDeclarativeBothProgrammaticBothRequiredRequired
Schema validationYesYesVia JPANoN/A5NoYesNo
Java supportYesYesYesYesYesYesNoNo
Kotlin supportFirst-classGoodGoodGoodGoodGoodNativeNative
CoroutinesYesNoNoNoNoNoYesLimited
Spring integrationYesYesNativeYesYesYesYesYes
Runtime mechanismCodegen6BytecodeBytecodeReflectionCodegenReflectionReflectionReflection
CommunityNewHugeHugeLargeMediumMediumMediumSmall

5 jOOQ generates code from the database schema, so schema validation is inherent in its code generation step.

6 Storm uses codegen with reflection fallback.


Storm vs JPA/Hibernate

JPA (typically implemented by Hibernate) is the most widely used persistence framework in the Java ecosystem. It provides a full object-relational mapping layer with managed entities and second-level caching. Storm takes a fundamentally different approach: entities are plain values with no managed state, and database interactions are explicit rather than implicit. This makes Storm simpler to reason about at the cost of JPA's more automated (but less predictable) features.

AspectStormJPA/Hibernate
EntitiesImmutable records/data classesMutable classes with getters/setters
PolymorphismSealed types (Single-Table, Joined, Polymorphic FK); STRING, INTEGER, CHAR discriminatorsClass hierarchy (Single-Table, Joined, Table-per-Class); STRING, INTEGER, CHAR discriminators
StateStateless; no persistence contextManaged entities
LoadingLoading in single queryLazy loading common
N+1 ProblemPrevented by design; requires explicit opt-inCommon pitfall
QueriesType-safe DSL, SQL TemplatesJPQL, Criteria API
CachingTransaction-scoped observationFirst/second level cache
TransactionsProgrammatic + @Transactional (Spring)@Transactional, JTA, container-managed
Schema ValidationProgrammatic + Spring Bootddl-auto=validate
Learning CurveGentle; SQL-likeSteep; many concepts
MagicWhat you see is what you getProxies, bytecode enhancement

Polymorphism differences. Storm and JPA overlap on Single-Table and Joined Table, but diverge beyond that. Storm adds Polymorphic FK, a two-column foreign key (type + id) that references independent tables with no shared base. This has no JPA equivalent (Hibernate offers the non-standard @Any annotation for a similar purpose). JPA adds Table-per-Class, which duplicates all fields into per-subtype tables and queries the base type via UNION ALL, and multi-level inheritance (e.g., AnimalPetCat). Storm intentionally limits hierarchies to a single sealed level, which covers the vast majority of real-world use cases while keeping SQL generation predictable.

When to Choose Storm

  • You want predictable, explicit database behavior
  • N+1 queries have been a recurring problem
  • You prefer immutable data structures
  • You value simplicity over complexity
  • You're using Kotlin and want idiomatic APIs

When to Choose JPA/Hibernate

  • You rely on second-level caching
  • You have complex multi-level inheritance hierarchies (Storm supports single-level sealed type polymorphism)
  • You have an existing JPA codebase to maintain
  • You need JPA compliance for vendor reasons
  • You want access to a large community and extensive resources

Storm vs Spring Data JPA

Spring Data JPA wraps JPA with a repository abstraction that derives query implementations from method names. It reduces boilerplate but inherits all of JPA's runtime complexity (proxies, managed state, lazy loading). Storm's Spring integration provides similar repository convenience with explicit query bodies instead of naming conventions.

AspectStormSpring Data JPA
FoundationCustom ORMJPA/Hibernate
PolymorphismSealed types (Single-Table, Joined, Polymorphic FK)Via JPA
RepositoriesInterface with default methodsInterface with method naming, @Query
Query MethodsExplicit DSL in method bodyDerived from method names, @Query
EntitiesRecords/data classesJPA entities
StateStatelessManaged
TransactionsProgrammatic + @Transactional (Spring)@Transactional (Spring-managed)

When to Choose Storm

  • You want stateless, immutable entities
  • You prefer explicit query logic over naming conventions
  • You want to avoid JPA's complexity

When to Choose Spring Data JPA

  • You need JPA features (lazy loading, caching)
  • You like query derivation from method names
  • You're already invested in the JPA ecosystem

Storm vs MyBatis

MyBatis is a SQL mapper that gives you full control over every query. You write SQL in XML files or annotations and map results to POJOs manually. Storm sits at a higher abstraction level, inferring SQL from entity definitions while still allowing raw SQL when needed. The trade-off is flexibility vs. automation: MyBatis never generates SQL for you, while Storm handles the common cases and lets you drop to raw SQL for complex queries.

AspectStormMyBatis
ApproachStateless ORMSQL mapper
PolymorphismSealed types (Single-Table, Joined, Polymorphic FK)Manual (via SQL)
SQL DefinitionInferred from entities, SQL Templates (optional)XML files or annotations
Result MappingAutomatic from entity definitionsManual XML/annotation mapping
EntitiesRecords/data classes with annotationsPOJOs, manual mapping
RelationshipsAutomatic via @FKManual nested queries/joins
Type SafetyCompile-time checkedString SQL, typed result mapping
N+1 ProblemPrevented by design; requires explicit opt-inManual optimization
TransactionsProgrammatic + @Transactional (Spring)Manual or Spring @Transactional
Dynamic SQLKotlin/Java codeXML tags (<if>, <foreach>)
Learning CurveGentle; annotation-basedModerate; XML knowledge helpful

When to Choose Storm

  • You want automatic entity mapping without XML
  • You prefer type-safe queries over string SQL
  • You want relationships handled automatically
  • You value compile-time safety
  • You're starting a new project without legacy SQL

When to Choose MyBatis

  • You have complex SQL that doesn't fit ORM patterns
  • You need fine-grained control over every query
  • You're working with legacy databases or stored procedures
  • You need XML-based SQL externalization

Storm vs jOOQ

jOOQ generates Java code from your database schema, providing a type-safe SQL DSL that mirrors the structure of your tables. Storm also treats the database schema as the source of truth, but instead of generating code from the schema, you write entity definitions that reflect it, and the metamodel is generated from those entities. Both frameworks provide compile-time type safety, but queries look very different. jOOQ excels at complex SQL (window functions, CTEs, recursive queries) where its DSL closely follows SQL syntax, but this means every join, column reference, and condition must be spelled out explicitly. Storm queries are more concise: the metamodel and automatic join derivation from @FK annotations let you write queries that focus on what you want rather than how to join it. Storm excels at entity-oriented operations where automatic relationship handling and repository patterns reduce boilerplate.

AspectStormjOOQ
ApproachSchema-reflective ORMSchema-driven code generation
PolymorphismSealed types (Single-Table, Joined, Polymorphic FK)Manual (via SQL DSL)
Type SafetyMetamodel from entitiesGenerated from schema
SetupDefine entities, code generationSchema, code generation
EntitiesRecords/data classes with EntityRecords or POJOs
Query StyleRepository + ORM DSL + SQL TemplatesSQL-like DSL
Query VerbosityConcise; auto joins from @FK, metamodel shortcutsVerbose; explicit joins, columns, and conditions
RelationshipsAutomatic from @FKManual joins
TransactionsProgrammatic + @Transactional (Spring)DSL context, Spring integration
LicenseApache 2.0Commercial for some DBs

When to Choose Storm

  • You prefer writing entity definitions that reflect the schema over generating code from it
  • You want concise, type-safe queries with automatic join derivation
  • You want automatic relationship handling
  • You value convention over configuration
  • You need a fully open-source solution

When to Choose jOOQ

  • You prefer pure SQL control
  • You want native DSL support for advanced SQL features (window functions, CTEs)
  • You want a thin layer over SQL with minimal runtime overhead

Storm vs JDBI

JDBI is a lightweight SQL convenience library that sits just above JDBC. It handles parameter binding, result mapping, and connection management without imposing an object model. Storm provides more structure with entity definitions, automatic relationship loading, and a repository pattern. Choose JDBI when you want minimal abstraction and full SQL control; choose Storm when you want the framework to handle common patterns while still allowing raw SQL escape hatches.

AspectStormJDBI
LevelStateless ORMLow-level SQL mapping
PolymorphismSealed types (Single-Table, Joined, Polymorphic FK)Manual
EntitiesAutomatic from annotationsManual mapping
RelationshipsAutomatic via @FKManual
Type SafetyMetamodel DSLString SQL
TransactionsProgrammatic + @Transactional (Spring)Manual, @Transaction annotation

When to Choose Storm

  • You want automatic entity mapping
  • You need relationship handling
  • You prefer type-safe queries over raw SQL

When to Choose JDBI

  • You want full SQL control
  • You prefer minimal abstraction
  • You have mostly complex queries that don't fit ORM patterns

Kotlin-Only Frameworks

The following frameworks are Kotlin-only. Storm supports both Kotlin and Java.

Storm vs Exposed

Exposed is JetBrains' official Kotlin database framework. It offers two APIs: a DSL that mirrors SQL syntax and a DAO layer for ORM-style access. Exposed defines tables as Kotlin objects rather than annotations on data classes. Storm and Exposed share the goal of idiomatic Kotlin database access but differ in entity design (mutable DAO entities vs. immutable data classes) and relationship loading strategy (lazy references vs. eager single-query loading).

AspectExposedStorm
LanguageKotlin onlyKotlin + Java
PolymorphismNoSealed types (Single-Table, Joined, Polymorphic FK)
APIsDSL (SQL) + DAO (ORM)Unified ORM + SQL Templates
Table DefinitionDSL objects (object Users : Table())Annotations on data classes
Entities (DAO)Mutable, extend Entity classImmutable data classes (Kotlin) / records (Java)
RelationshipsLazy references, manual loadingLoading in single query
N+1 ProblemPossible with DAOPrevented by design; requires explicit opt-in
CoroutinesSupported (added later)First-class from the start
Type SafetyColumn referencesMetamodel DSL
TransactionsRequired transaction {} blockOptional, programmatic + declarative

When to Choose Storm

  • You need Kotlin and Java support
  • You want immutable entities without base class inheritance
  • You prefer annotation-based entity definitions
  • N+1 queries are a concern
  • You want relationships loaded automatically
  • You need full support for transaction propagation modes

When to Choose Exposed

  • You're building a Kotlin-only project
  • You prefer DSL-based table definitions
  • You want to switch between SQL DSL and DAO styles
  • You like the JetBrains ecosystem integration
  • You need fine-grained control over lazy loading
  • You need R2DBC support for reactive database access*

*Storm uses JDBC and relies on JVM virtual threads for non-blocking I/O instead of R2DBC.

Storm vs Ktorm

Ktorm is a lightweight Kotlin ORM that uses entity interfaces and DSL-based table definitions. It requires no code generation and has minimal dependencies. Storm differs primarily in its use of immutable data classes (instead of mutable interfaces), automatic relationship loading, and optional metamodel generation for compile-time type safety.

AspectKtormStorm
LanguageKotlin onlyKotlin + Java
PolymorphismNoSealed types (Single-Table, Joined, Polymorphic FK)
EntitiesInterfaces extending EntityData classes with annotations
Table DefinitionDSL objects (object Users : Table<User>)Annotations on data classes
Query StyleSequence API, DSLORM DSL + SQL Templates
RelationshipsReferences, manual loadingAutomatic loading
N+1 ProblemPossiblePrevented by design; requires explicit opt-in
Code GenerationNone requiredOptional metamodel
ImmutabilityMutable entity interfacesImmutable data classes
CoroutinesLimitedFirst-class support
TransactionsuseTransaction {} blockProgrammatic + @Transactional (Spring)

When to Choose Storm

  • You need Kotlin and Java support
  • You want immutable data classes, not interfaces
  • You prefer annotation-based definitions
  • N+1 prevention is important
  • You want automatic relationship loading

When to Choose Ktorm

  • You're building a Kotlin-only project
  • You prefer no code generation
  • You like the Sequence API style
  • You want a lightweight, minimal dependency footprint
  • You prefer DSL-based table definitions

Summary

Storm is a newer framework, so community resources and third-party tutorials are still growing. However, the API is designed to be intuitive for developers familiar with SQL and Kotlin and modern Java.

Choose Storm if you value:

  • Simplicity over complexity
  • Predictability over magic
  • Immutability over managed state
  • Explicit over implicit behavior
  • Kotlin and modern Java development with first-class support for both

Ready to try it? See the Getting Started guide.