Complete Guide to Database Migrations with Spring Boot, PostgreSQL, and Flyway

September 2, 2026

Flyway Inner

Introduction

When building backend applications using relational databases like PostgreSQL, one of the biggest
challenges is safely evolving the database schema after real data already exists.

A very common beginner approach is:

spring.jpa.hibernate.ddl-auto=create

or:

spring.jpa.hibernate.ddl-auto=update

This may work during early development, but once your application contains real production data, automatic schema recreation becomes dangerous.

This document explains:
  • What database migrations are
  • Why migrations are important
  • How Flyway works internally
  • How to use Flyway with Spring Boot and PostgreSQL
  • How migrations behave in production
  • How teams work with migrations
  • Safe database evolution strategies
  • Real-world examples

1. What is a Database Migration?

A database migration is:
  • A version-controlled database change that evolves the schema safely over time.
Think of migrations like Git commits for your database. Example migration timeline:
VersionPurpose
V1Create users table
V2Add email column
V3Migrate existing data
V4Add indexes
V5Remove deprecated columns

Instead of recreating the entire database, migrations apply only incremental changes.

2. Why Hibernate Auto-DDL is Dangerous

Using create:

spring.jpa.hibernate.ddl-auto=create

Problems:
  • Drops and recreates schema
  • Deletes all existing data
  • Unsafe for production

Using update:

spring.jpa.hibernate.ddl-auto=update

Problems:
  • Hibernate guesses schema changes automatically
  • Unpredictable for complex relational structures
  • No migration history
  • No rollback tracking
  • Unsafe for teams

3. Recommended Production Setup

Production systems usually use:

spring.jpa.hibernate.ddl-auto=validate

This means:
  • Hibernate validates schema
  • Flyway controls schema evolution
  • Database changes become explicit and safe

4. How Flyway Works

Flyway works by:

  1. Reading migration files
  2. Checking migration history
  3. Running only missing migrations
  4. Recording execution status

5. Flyway Architecture

Spring Boot Application

Flyway

PostgreSQL Database

Flyway itself is NOT a separate database.It simply:
  • connects to PostgreSQL,
  • executes SQL files,
  • tracks execution history.

6. The flyway_schema_history Table

Flyway automatically creates:

flyway_schema_history

inside your PostgreSQL database.This table tracks:
  • migration versions
  • filenames
  • checksums
  • timestamps
  • success/failure status
Example:
VersionDescriptionSuccess
1create users tabletrue
2add email columntrue
3migrate existing datatrue

This table is very small and never becomes a storage issue.

7. Setting Up Flyway in Spring Boot

Maven Dependency:

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>

Application Properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/project_db
spring.datasource.username=postgres
spring.datasource.password=postgres

spring.jpa.hibernate.ddl-auto=validate
spring.flyway.enabled=true

8. Migration Folder Structure

Create folder:

src/main/resources/db/migration

Example files:

V1__create_users_table.sql
V2__add_email_column.sql
V3__migrate_existing_data.sql

9. Flyway Naming Rules

Correct format:

V<version>__<description>.sql

Examples:

V1__create_users.sql
V2__add_email.sql
V3__migrate_data.sql

Incorrect:

create_users.sql
migration1.sql

10. First Migration Example

V1__create_users_table.sql

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    name VARCHAR(255),
    age INT
);

11. Spring Boot Entity Example

@Entity
@Table(name = “users”)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private Integer age;
}

12. Application Startup Process

When Spring Boot starts:
  1. Connects to PostgreSQL
  2. Flyway checks flyway_schema_history
  3. Executes pending migrations
  4. Records migration status
  5. Hibernate validates schema
  6. Application starts

13. Real Migration Scenario

Suppose the application already contains:

IDNameAge
1John Doe25
Now business requires:
  • email column

14. Add New Column Safely

V2__add_email_column.sql

ALTER TABLE users
ADD COLUMN email VARCHAR(255);

Data remains safe.
Result:

IDNameAgeEmail
1John Doe25null

15. Data Migration Example

Suppose existing users need generated emails.

V3__migrate_existing_data.sql

UPDATE users
SET email =
    LOWER(REPLACE(name, ‘ ‘, ‘.’))
    || ‘@example.com’
WHERE email IS NULL;

Result:

IDNameEmail
1John Doejohn.doe@example.com

16. First Production Deployment

Suppose production database is initially empty.
Flyway executes:

V1 -> create table
V2 -> add email column
V3 -> migrate data

Even if no rows exist:

UPDATE users SET ...

is still valid.
PostgreSQL simply updates:

0 rows

No failure occurs.

17. Important Migration Philosophy

Migrations represent: Complete database history.

A fresh environment can rebuild schema from version 1 to latest.

18. Why Old Migrations Must Never Be Deleted

Migration files are part of application history.

They are required for:

  • new environments
  • testing databases
  • CI/CD pipelines
  • production deployments
  • new developers

Always commit migration files to Git.

19. Team Collaboration Example

Suppose multiple developers use same database.
Developer A creates:

V10__add_email.sql

Runs application.
Flyway records version 10 in:

flyway_schema_history

Developer B pulls latest code.
When Developer B starts application:
Flyway sees:

V10 already executed

Migration is skipped automatically.

20. Recommended Team Setup

Professional teams usually use:

Local Development

Each developer uses:

  • separate local PostgreSQL database

Shared Environments

Separate:

  • development
  • staging
  • QA
  • production

21. Safe Database Evolution Strategy

Production-safe migrations follow:

Expand
→ Migrate Data
→ Switch Application
→ Remove Old Structure

22. Example: Splitting Name Column

Current schema:

IDName
1John Doe

Business requires:
first_name
last_name

Step 1 — Expand Schema

ALTER TABLE users
ADD COLUMN first_name VARCHAR(100);

ALTER TABLE users
ADD COLUMN last_name VARCHAR(100);

Step 2 — Backfill Data

UPDATE users
SET
first_name = split_part(name, ‘ ‘, 1),
last_name = split_part(name, ‘ ‘, 2);

Step 3 — Update Application

Application now uses:

  • first_name
  • last_name

instead of:

  • name

Step 4 — Remove Old Column

ALTER TABLE users
DROP COLUMN name;

No data loss occurs.

23. Safe Migration Principles

Prefer Additive Changes

Safer:

  • add table
  • add column
  • add index

More dangerous:

  • drop column
  • rename column
  • type conversion

Keep Migrations Small

GOOD:

V101 add email
V102 migrate email data
V103 add constraint

BAD:

One huge 5000-line migration

Never Modify Old Executed Migrations

BAD:
Editing:

V2__add_email.sql

after production execution.
GOOD:
Create:

V3__modify_email_constraints.sql

instead.

24. Large Project Scaling

Flyway works perfectly fine with:

  • 150 tables
  • 500 tables
  • thousands of migrations
  • millions of records

Flyway only executes pending migrations.

It does NOT recreate entire schema.

25. Common Beginner Misconception

Incorrect mindset:

Entity changes
→ recreate database

Correct professional mindset:

Entity changes
→ create migration
→ evolve schema safely

26. Production Deployment Flow

Typical deployment:

Deploy new application
        ↓
Flyway checks migration history
        ↓
Runs pending migrations
        ↓
Schema safely updated
        ↓
Application starts

No table recreation.
No data loss.

27. What Flyway Does Automatically

Flyway automatically:

  • creates flyway_schema_history
  • tracks migration versions
  • executes migrations sequentially
  • skips already executed migrations
  • records success/failure
  • validates checksums

28. What Developers Must Do Manually

Developers must:

  • create migration files
  • write SQL changes manually
  • commit migrations to Git
  • design safe schema evolution

Flyway does NOT automatically infer entity changes.

29. Recommended Learning Path

To master production-grade relational database evolution, learn:

PostgreSQL

  • transactions
  • indexes
  • constraints
  • locks
  • execution plans
  • concurrent indexes

Migration Engineering

  • backward compatibility
  • zero downtime deployments
  • rolling deployments
  • data backfills
  • large-table migration strategies

30. Final Takeaway

The goal is NOT:

“How do I recreate my schema?”

The real engineering goal is:

“How do I evolve a live relational database safely?”

That mindset is one of the foundations of scalable backend engineering.

Get In Touch

"Share your ideas and get the best software service in the industry."

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *