Exposed 1.0.0-beta-3 Help

Migrations

Managing database schema changes is a critical part of application development. Exposed offers several tools to help with schema migrations, allowing you to evolve your database alongside your codebase.

While Exposed provides basic migration support through SchemaUtils, the MigrationUtils methods from the exposed-migration package provide a more structured and production-ready way to manage schema changes. They allow you to inspect differences between the current database state and your defined table schema and to generate or apply migration scripts accordingly.

Adding dependencies

To use the methods provided by MigrationUtils, include the exposed-migration artifact in your build script:

implementation("org.jetbrains.exposed:exposed-migration:1.0.0-beta-3")

Aligning the database schema

When you need to bring your database schema in line with your current Exposed table definitions, you have three options:

  1. Generate only missing column statements

  2. Generate all required statements for database migration

  3. Generate a migration script

Generate missing column statements

If you only need the SQL statements that create any columns that are missing from the existing tables in the database, use the SchemaUtils.addMissingColumnsStatements() function:

val missingColStatements = SchemaUtils.addMissingColumnsStatements( UsersTable )

This function returns a collection of string SQL statements, ensuring that any column-associated constraints are aligned. As it adds missing columns, it simultaneously adds any associated constraints such as primary keys, indexes, and foreign keys that may be absent.

Generate all required statements

To compare your live database schema against your current Exposed table definitions and generate all statements required to align the two, use the MigrationUtils.statementsRequiredForDatabaseMigration() function:

val statements = MigrationUtils.statementsRequiredForDatabaseMigration( UsersTable )

The returned collection of string SQL statements may include CREATE, ALTER, and DROP operations — including potentially destructive actions like DROP COLUMN or DELETE, so review them carefully before choosing to execute them.

Generate a migration script

To generate a migration script based on schema differences between your database and the current Exposed model, use the MigrationUtils.generateMigrationScript() function:

MigrationUtils.generateMigrationScript( UsersTable, scriptDirectory = MIGRATIONS_DIRECTORY, scriptName = "V2__Add_primary_key", )

This method allows you to see what the migration script will look like before applying the migration. If a migration script with the same name already exists, its content will be overwritten.

Validating the database schema

Before applying any migrations, it's useful to validate that your Exposed schema definitions match the actual state of the database. While the primary use of schema alignment methods is to generate SQL statements and migration scripts, these same methods can also serve as pre-checks — especially when used to detect unexpected changes.

Exposed provides several low-level APIs that support schema validation and can be integrated into custom migration or deployment pipelines. These methods are also used internally by Exposed to generate migration statements, but you can also use them for more precise checks.

Check for existence of a database object

To determine if a specific database object is already present, use one of the following methods:

Structural integrity checks

To evaluate whether a table has excessive indices or foreign keys, which might indicate schema drift or duplication, use one of the following SchemaUtils methods:

Database metadata inspection

To retrieve metadata from the current dialect to compare with your defined Exposed schema, use one of the following currentDialect methods:

Legacy columns cleanup

As your schema evolves, it's common to remove or rename columns in your table definitions. However, old columns may still exist in the database unless explicitly dropped.

The MigrationUtils.dropUnmappedColumnsStatements() function helps identify columns that are no longer present in your current table definitions and returns the SQL statements to remove them:

val dropStatements = MigrationUtils.dropUnmappedColumnsStatements( UsersTable )

Logging

By default, each method provided by MigrationUtils logs descriptions and the execution time of each intermediate step. These logs are emitted at the INFO level and can be disabled by setting withLogs to false:

MigrationUtils.statementsRequiredForDatabaseMigration( UsersTable, withLogs = false )

Limitations

While Exposed's migration tools are powerful, there are some limitations:

  • You must still implement and manage your own migration flow.

  • Automatic migration execution is not provided — scripts must be run manually or integrated into your deployment process. This limitation is already addressed in the Gradle migration plugin feature request.

  • Some database-specific behaviors, such as SQLite's limited ALTER TABLE support, may lead to partial or failed migrations if not reviewed.

  • Destructive operations like DROP COLUMN or DROP SEQUENCE can be included — caution is advised.

We recommend that you always manually review generated diffs or scripts before applying them to a live database.

SQLite

SQLite has strict limitations around the ALTER TABLE ADD COLUMN statement. For example, it does not allow adding a new column without a default value under certain conditions. Since Exposed cannot account for all of SQLite’s specific constraints, it will still generate the expected SQL statement. It is up to you to review the generated SQL and avoid attempting migrations that are incompatible with SQLite’s rules. If such a statement is executed, it will fail at runtime.

PostgreSQL

When running on PostgreSQL, the functions to align the database schema also check for inconsistencies between table definitions and sequences (especially those tied to SERIAL columns on IdTable).

Sequences manually created with CREATE SEQUENCE and not linked to a table are ignored. No DROP statements are generated for such sequences.

Feature requests

Gradle plugin

A Gradle plugin to simplify SQL migrations is in development. A proposed design for Flyway integration has been presented and is actively being implemented. To show interest or get involved, see the YouTrack issue for creating the migration Gradle plugin.

Maven and Liquibase integration

Exposed does not currently offer a Maven plugin or Liquibase integration — share your interest to help shape future support:

Last modified: 03 July 2025