documentation-website/Writerside/topics/exposed-maven-plugin.md
The Exposed Maven plugin provides build-time tooling for working with Exposed-based database schemas in Maven projects.
Its primary feature is generating SQL migration scripts by comparing Exposed table definitions with an existing database schema.
Testcontainers)To install the plugin, add it to the <build><plugins> section of your <path>pom.xml</path> file:
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.exposed.plugin</groupId>
<artifactId>exposed-maven-plugin</artifactId>
<version>%exposed_version%</version>
</plugin>
</plugins>
</build>
To generate migration scripts based on the difference between your existing database schema and your Exposed table
definitions, invoke the generate-migration goal:
mvn exposed:generate-migrations
Generated files are written to the configured output directory.
You can bind migration generation to a Maven lifecycle phase by adding an <executions> block to the plugin
configuration. For example, to generate migrations during the process-classes phase:
<plugin>
<groupId>org.jetbrains.exposed.plugin</groupId>
<artifactId>exposed-maven-plugin</artifactId>
<version>%exposed_version%</version>
<executions>
<execution>
<id>generate-migrations</id>
<phase>process-classes</phase>
<goals>
<goal>generate-migrations</goal>
</goals>
</execution>
</executions>
</plugin>
Configure the plugin using the <configuration> block inside the plugin entry in your <path>pom.xml</path> file.
At minimum, configure the following parameters:
tablesPackage as the package name where Exposed table definitions are located.Testcontainers configuration.To configure a database connection, set the databaseUrl, databaseUser, and databasePassword parameters:
<plugin>
<groupId>org.jetbrains.exposed.plugin</groupId>
<artifactId>exposed-maven-plugin</artifactId>
<version>%exposed_version%</version>
<configuration>
<tablesPackage>com.example.db.tables</tablesPackage>
<databaseUrl>jdbc:postgresql://localhost:5432/mydb</databaseUrl>
<databaseUser>postgres</databaseUser>
<databasePassword>password</databasePassword>
</configuration>
</plugin>
Testcontainers {id="testcontainers-config"}To configure a Testcontainers connection, set the testContainersImageName parameter:
<plugin>
<groupId>org.jetbrains.exposed.plugin</groupId>
<artifactId>exposed-maven-plugin</artifactId>
<version>%exposed_version%</version>
<configuration>
<tablesPackage>com.example.db.tables</tablesPackage>
<testContainersImageName>postgres:latest</testContainersImageName>
</configuration>
</plugin>
For more details and supported database container images, see .
{style="tip"}
When
testContainersImageNameis configured, the plugin usesTestcontainersinstead of a direct database connection for schema generation.
{style="note"}
To override any plugin parameter on the command line, use the matching exposed.migrations.<name> system property:
mvn exposed:generate-migrations \
-Dexposed.migrations.tablesPackage=com.example.db.tables \
-Dexposed.migrations.databaseUrl=jdbc:postgresql://localhost:5432/mydb \
-Dexposed.migrations.databaseUser=postgres \
-Dexposed.migrations.databasePassword=password
Optionally, you can configure the following parameters for additional control over migration generation and file naming:
<deflist type="medium"> <def id="file-directory"> <title><code>fileDirectory</code></title>Directory where migration scripts are stored.
Defaults to src/main/resources/db/migration under the project base directory.
Prefix used for migration script names.
Defaults to "V".
</def>
<def>
Version format used for migration script names. For supported values, see version formats.
Defaults to a timestamp in the yyyyMMddHHmmss format.
</def>
<def>
Separator used in migration script names.
Defaults to "__".
</def>
<def>
Whether the descriptive part of migration script names is converted to uppercase.
Defaults to true.
</def>
<def>
File extension used for migration scripts.
Defaults to ".sql".
</def>
</deflist>
Example:
<plugin>
<groupId>org.jetbrains.exposed.plugin</groupId>
<artifactId>exposed-maven-plugin</artifactId>
<version>%exposed_version%</version>
<configuration>
<tablesPackage>com.example.db.tables</tablesPackage>
<databaseUrl>jdbc:postgresql://localhost:5432/mydb</databaseUrl>
<databaseUser>postgres</databaseUser>
<databasePassword>password</databasePassword>
<fileDirectory>${project.basedir}/src/main/resources/db/migration</fileDirectory>
<filePrefix>V</filePrefix>
<fileVersionFormat>TIMESTAMP_ONLY</fileVersionFormat>
<fileSeparator>__</fileSeparator>
<useUpperCaseDescription>true</useUpperCaseDescription>
<fileExtension>.sql</fileExtension>
</configuration>
</plugin>
The plugin supports the following fileVersionFormat values:
Example: V20260417195521__CREATE_TABLE_USERS.sql
</def>
<def>
Example: V202604171955__CREATE_TABLE_USERS.sql
</def>
<def>
Example: V3_20260417195521__CREATE_TABLE_USERS.sql
</def>
<def>
Example: V3_202604171955__CREATE_TABLE_USERS.sql
</def>
<def>
Example: V3_1__CREATE_TABLE_USERS.sql
</def>
<def>
Example: V3__CREATE_TABLE_USERS.sql
</def>
</deflist>
For version formats that include a major version, the plugin scans the configured fileDirectory to determine the
next available version. If the directory is empty, or if no compatible migration files are found, numbering starts at 1.
By default, migration scripts use the following naming pattern:
<prefix><version><separator><description><extension>
For example:
V20260417195521__CREATE_TABLE_USERS.sql
The generated description (CREATE_TABLE_USERS) is derived from the generated SQL statement and
typically follows this format:
<OPERATION>_<OBJECT>_<IDENTIFIER>_<EXTRA>
When a migration contains multiple SQL statements, the description is usually derived from the first significant statement.
CREATE TABLE statement.CREATE TABLE statement
instead of CREATE SEQUENCE.If the plugin cannot derive a standard description, it falls back to a generic name, such as CUSTOM_STATEMENT_12345.
You can override the generated filename by passing the exposed.migrations.filename system property to the generate-migration
goal:
mvn exposed:generate-migrations -Dexpose.migrations.filename=V0__initialize_schema.sql
When
exposed.migrations.filenameis specified, the plugin generates a single migration script containing all migration statements, even if the schema diff affects multiple tables.
{style="note"}
Testcontainers {id="use-testcontainers"}Testcontainers is a Java library that lets you run temporary
Docker containers during tests or build tasks.
You can use Testcontainers to start a disposable database instance automatically while generating migration scripts.
Docker must be installed and running to use
Testcontainers.
{style="note"}
Testcontainers workflowWhen using Testcontainers, the Exposed Maven plugin performs the following steps:
If the configured migration directory contains existing migration scripts, the plugin applies them using Flyway before generating new migrations.
This ensures that newly generated migration scripts are based on the latest schema state, including changes introduced by previous migrations.
The plugin supports the following database container images:
| Database | Container images |
|---|---|
| MySQL | mysql, mysql:latest, or other tags |
| MariaDB | mariadb, mariadb:latest , or other tags |
| PostgreSQL | postgres, postgres:latest , or other tags |
| SQL Server | mcr.microsoft.com/mssql/server, mcr.microsoft.com/mssql/server:2025-latest, or other tags |
| Oracle | Images starting with container-registry.oracle.com/,gvenzl/oracle- or oracle/ |
The Exposed Maven plugin generates migration scripts, but it does not apply them to your database automatically.
After generating migration scripts, review and apply them using your existing database migration workflow. For example, you can:
After applying the generated scripts, your database schema should match your current Exposed table definitions.