๐๐จ๐ฐ ๐๐จ ๐ฒ๐จ๐ฎ ๐ฆ๐ข๐ ๐ซ๐๐ญ๐ ๐ฌ๐๐ก๐๐ฆ๐ ๐๐ก๐๐ง๐ ๐๐ฌ ๐ฌ๐๐๐๐ฅ๐ฒ ๐ข๐ง ๐๐ฉ๐ซ๐ข๐ง๐ ๐๐จ๐จ๐ญ ๐ฐ๐ข๐ญ๐ก ๐๐จ๐ฌ๐ญ๐ ๐ซ๐๐๐๐? ๐ฐ๐ข๐ญ๐ก ๐๐๐๐ฅ-๐๐ข๐ฆ๐ ๐๐ฑ๐๐ฆ๐ฉ๐ฅ๐
=================================
In Spring Boot projects, I handle schema migrations using a versioned migration tool like Flyway or Liquibase, rather than relying on Hibernate auto-DDL. This gives us controlled, repeatable, and auditable database changes across environments
Each schema change is written as a migration script and versioned โ for example, adding a column, creating an index, or modifying a constraint. These migrations are applied automatically at application startup or during deployment, and the tool tracks which migrations have already run
To keep migrations safe, I follow a few best practices. First, migrations are backward-compatible whenever possible โ for example, adding new nullable columns before removing old ones. Destructive changes like dropping columns are done in later releases after the application code no longer depends on them
Second, all migrations are tested in lower environments using production-like data. We also make sure migrations are idempotent and transactional, which PostgreSQL supports well, so failures can be rolled back safely.
Finally, migrations are part of the CI/CD pipeline, and production changes are always backed up. This way, schema evolution is predictable, reversible when needed, and aligned with application releases
๐๐๐๐ฅ-๐๐ข๐ฆ๐ ๐๐ฌ๐ ๐๐๐ฌ๐: ๐๐๐๐๐ฅ๐ฒ ๐๐๐๐ข๐ง๐ ๐ ๐๐จ๐ง-๐๐ฎ๐ฅ๐ฅ๐๐๐ฅ๐ ๐๐จ๐ฅ๐ฎ๐ฆ๐ง
---------------------------------------
๐๐๐๐ง๐๐ซ๐ข๐จ :
We had a users table in PostgreSQL, and the business requirement was to add a status field to track whether a user is ACTIVE, SUSPENDED, or DELETED. The application is already live with millions of records
๐๐ซ๐จ๐๐ฅ๐๐ฆ
We canโt directly add a NOT NULL column, because existing rows donโt have values and it would either fail or cause downtime
๐๐ญ๐๐ฉ 1: ๐๐๐ ๐ญ๐ก๐ ๐๐จ๐ฅ๐ฎ๐ฆ๐ง ๐๐ฌ ๐ง๐ฎ๐ฅ๐ฅ๐๐๐ฅ๐
ALTER TABLE users ADD COLUMN status VARCHAR(20);
This change is backward-compatible and doesnโt break the running application
๐๐ญ๐๐ฉ 2: ๐๐๐๐ค๐๐ข๐ฅ๐ฅ ๐๐ฑ๐ข๐ฌ๐ญ๐ข๐ง๐ ๐๐๐ญ๐
UPDATE users SET status = 'ACTIVE' WHERE status IS NULL;
This can be done in batches to avoid long-running locks
๐๐ญ๐๐ฉ 3: ๐๐ฉ๐๐๐ญ๐ ๐๐ฉ๐ฉ๐ฅ๐ข๐๐๐ญ๐ข๐จ๐ง ๐๐จ๐๐
We update the Spring Boot code to always write status for new users
๐๐ญ๐๐ฉ 4: ๐๐๐ ๐๐๐ ๐๐๐๐ ๐๐จ๐ง๐ฌ๐ญ๐ซ๐๐ข๐ง๐ญ ๐ข๐ง ๐ ๐ฅ๐๐ญ๐๐ซ ๐ฆ๐ข๐ ๐ซ๐๐ญ๐ข๐จ๐ง
ALTER TABLE users ALTER COLUMN status SET NOT NULL;
At this point, the database constraint enforces data integrity safely.โ
All these steps are implemented as separate Flyway or Liquibase migrations, versioned and applied through CI/CD. Each release moves the schema forward without breaking running code