Skip to main content

5.6 Database Migrations with Flyway

← Back to Chapter 5: Spring Data JPA, Hibernate & Database

Relying on Hibernate's spring.jpa.hibernate.ddl-auto=update in production is dangerous because it can cause data loss, lock tables unpredictably, and cannot handle complex column transforms. Flyway provides deterministic, version-controlled database schema migrations.


1. Why Dedicated Migration Tools?​

  • Auditability: Every schema modification is version-controlled in Git alongside application code.
  • Repeatability: Guaranteed identical schema state across local, staging, and production environments.
  • Continuous Deployment: Migrations execute automatically on application startup before the Hibernate EntityManagerFactory initializes.

2. Flyway Migration File Naming Rules​

Flyway parses filenames strictly based on conventions:

V1__create_users_table.sql
V2__add_email_unique_index.sql
V2.1__add_user_profile_columns.sql
R__refresh_customer_views.sql
Prefix ──> [ V ] (Versioned) or [ R ] (Repeatable)
Version ─> [ 1.0 ] (Numbers separated by dots or underscores)
Separator> [ __ ] (EXACTLY TWO UNDERSCORES)
Desc ────> [ create_users_table ]
Suffix ──> [ .sql ]

3. Migration Example & Production Configuration​

Migration File: src/main/resources/db/migration/V1__init_schema.sql​

CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY,
full_name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
);

CREATE INDEX idx_customers_email ON customers(email);

application.yml Production Configuration:​

spring:
jpa:
hibernate:
ddl-auto: validate # NEVER update or create-drop in production!
flyway:
enabled: true
baseline-on-migrate: true
locations: classpath:db/migration

The flyway_schema_history Table​

Flyway creates and manages a tracking table in your database recording:

  • version: The script version applied.
  • checksum: Cryptographic hash of the script content (fails startup if an applied script was tampered with!).
  • installed_on: Timestamp of execution.
  • execution_time: Latency in milliseconds.