Spring Boot
Hibernate
Flyway
Boot Order
Database Migration

Spring Boot Hibernate and Flyway boot order

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In a typical Spring Boot application, Flyway should migrate the database before Hibernate starts validating or using the schema. That boot order matters because your entity mappings are written against the expected current schema, not against yesterday's schema. If Hibernate starts too early, you get validation failures, missing-table errors, or misleading startup behavior.

The Normal Boot Order

In the usual Spring Boot setup with one main datasource:

  1. the datasource is created
  2. Flyway runs pending migrations
  3. JPA and Hibernate initialize against the migrated schema

That is the behavior most teams want. Flyway updates the database structure, then Hibernate validates or uses it.

A common configuration looks like this:

properties
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.jpa.hibernate.ddl-auto=validate

Using ddl-auto=validate is important in Flyway-managed systems because it tells Hibernate to verify the schema instead of trying to create or modify it itself.

Why Flyway Should Go First

Flyway is the schema authority. Hibernate should not be inventing schema changes in production when Flyway is already tracking them as versioned migrations.

For example, suppose you add a new email column to a users table and your entity now expects it:

java
1@Entity
2class UserEntity {
3
4    @Id
5    private Long id;
6
7    @Column(nullable = false)
8    private String email;
9}

If Flyway has not yet applied the migration, Hibernate can fail during startup because the database does not match the entity mapping.

That is why the desired sequence is always migration first, ORM second.

A Good Flyway Workflow

A typical Flyway migration might be:

sql
-- V3__add_email_to_users.sql
ALTER TABLE users ADD COLUMN email VARCHAR(255) NOT NULL;

Then on startup:

  • Flyway applies V3
  • Hibernate validates that email exists
  • the application starts cleanly

This is far more predictable than relying on ddl-auto=update, which can make uncontrolled schema changes and drift away from your audited migration history.

What Can Disrupt the Expected Order

The normal order is reliable in the common case, but you can disrupt it with custom configuration.

Examples include:

  • multiple datasources with custom bean wiring
  • manually constructed EntityManagerFactory beans
  • disabling Flyway accidentally in one environment
  • using SQL init scripts and Flyway together without a clear strategy

If you step outside Spring Boot's default autoconfiguration path, verify the bean dependencies explicitly. The more custom the startup configuration becomes, the less you should assume the default ordering still protects you.

ddl-auto Choices With Flyway

When Flyway manages schema changes, the most common Hibernate settings are:

  • 'validate in production and often in development'
  • 'none in some specialized setups'

Usually avoid:

  • 'update because it competes with Flyway for schema ownership'
  • 'create or create-drop except for throwaway test environments'

If both Flyway and Hibernate try to mutate the schema, you lose the clarity and reproducibility Flyway is supposed to provide.

Testing the Startup Contract

A simple integration test can confirm that migrations run before your repositories and entity manager are used.

java
1@SpringBootTest
2class ApplicationStartupTest {
3
4    @Autowired
5    private javax.sql.DataSource dataSource;
6
7    @Test
8    void contextLoads() {
9        assertNotNull(dataSource);
10    }
11}

The value of the test is not the assertion itself. It is the fact that the application context must complete startup successfully with Flyway and JPA configured together.

Common Pitfalls

The most common mistake is using Flyway for migrations while leaving spring.jpa.hibernate.ddl-auto=update. That creates two schema managers with conflicting responsibilities.

Another mistake is assuming Boot order will stay correct after introducing multiple datasources or custom JPA beans. Custom wiring can break the default lifecycle.

Developers also sometimes disable Flyway in one environment and then wonder why Hibernate validation fails there but not elsewhere.

Finally, remember that startup order is not the whole story. Your migration scripts still need to be correct, idempotent where appropriate, and aligned with entity changes.

Summary

  • In a normal Spring Boot setup, Flyway should run before Hibernate initializes the schema.
  • Use Flyway as the source of truth for schema changes and let Hibernate validate.
  • 'spring.jpa.hibernate.ddl-auto=validate is usually the right companion setting.'
  • Custom datasources and bean wiring can break the expected default ordering.
  • If Flyway manages the schema, avoid letting Hibernate mutate it independently.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.