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:
Aligning the database schema
When you need to bring your database schema in line with your current Exposed table definitions, you have three options:
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:
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:
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:
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:
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
:
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
orDROP 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: