Tutorials/Exposed vs Storm: schema

Who owns the schema

A genuine philosophical difference, with a winner on each side. Exposed can generate the schema from code, which is excellent early on. Storm assumes the database owns the schema and verifies that your model still tells the truth about it.

Series · Exposed to Storm4 min readKotlin

01The task

Two moments in a project's life: day one, when you want tables to exist with minimal fuss, and year two, when the schema is production data under migration control and the risk is drift between what the code believes and what the database is.

02The Exposed way

Because Exposed's table objects fully describe columns and types, they can create the schema:

Setup.kt Kotlin · Exposed
1
2
3
4
// The table objects can create the schema, a real convenience
transaction {
    SchemaUtils.create(Cities, Users)
}

For prototypes, tests, and greenfield day one, this is genuinely great, and Storm has no equivalent. For evolution, Exposed 1.0 adds MigrationUtils (in the exposed-migration modules), which generates the statements a schema change requires; teams typically feed those into a migration tool such as Flyway or Liquibase. The table objects remain a second description of the schema, kept in sync with the migrations by discipline.

03The Storm way

Storm starts from the other end: the database schema, evolved by your migration tool, is the source of truth, and entities are a typed view of it. What Storm adds is verification that the view is still accurate:

Startup.kt Kotlin · Storm
1
2
3
4
5
6
7
8
// The database owns the schema; Storm checks that the model matches
val orm = dataSource.orm

// Inspect programmatically ...
val errors: List<String> = orm.validateSchema()

// ... or fail fast at startup
orm.validateSchemaOrThrow()

Validation checks entities and projections against the live schema: missing tables and columns, type incompatibilities, nullability mismatches, primary key mismatches, and missing constraints. With the Spring Boot starter it runs at startup, configured by property:

application.yml YAML · Storm
1
2
3
4
5
# application.yml (Spring Boot starter)
storm:
  validation:
    schema_mode: fail   # none | warn | fail
    strict: true        # promote drift warnings to errors, useful in CI

With strict: true in CI, a migration that quietly diverges from the model fails the build instead of failing a query in production weeks later. For tests, @StormTest runs your real schema scripts, so the same migrations that shape production shape the test database.

04The trade

ExposedStorm
Creating the schemaSchemaUtils.create(...) from table objectsYour migration tool; Storm does not generate DDL
Evolving the schemaMigrationUtils generates statements; a migration tool applies themMigration tool; the model follows, verified
Detecting driftDiscovered when a query failsvalidateSchema(), startup mode, strict CI mode
Source of truthThe table objects, until migrations take overThe database, always

If your project lives mostly in the prototype phase, Exposed's generation is the nicer workflow and this page happily concedes it. Storm's bet is that schemas spend most of their lives owned by migrations, and that the valuable tool in that long phase is the one that catches drift early.

05Keep going

The reference documentation covers the mechanics in depth: