A clean, structured, and beginner-friendly guide for learning Flyway
database migrations using Spring Boot, Kotlin, and
PostgreSQL.
This project emphasizes migration discipline, schema organization, and a
smooth local development workflow using Docker.
This learning project demonstrates how to:
- Use versioned, repeatable, and undo Flyway migrations\
- Organize migrations in a clean folder structure\
- Develop inside isolated containers or local mode\
- Work with a custom schema (
dime)\ - Query database metadata through a simple API\
- Enforce strict commit message rules and PR workflow\
- Start/stop the DB or full stack using Gradle tasks
.
├── docker/
│ ├── Dockerfile
│ ├── docker-compose.db.yml
│ └── docker-compose.dev.yml
├── src/
│ ├── main/
│ │ ├── kotlin/
│ │ │ └── learning/flyway/actual_application/controller/
│ │ │ └── PublicController.kt
│ │ └── resources/
│ │ ├── application.properties
│ │ └── db/
│ │ ├── migration/
│ │ │ ├── versioned/
│ │ ├── repeatable/
│ │ └── undo/
├── build.gradle.kts
└── README.md
Location: db/migration/versioned/
Run exactly once, in order.
Use for: - Creating/altering tables - Adding constraints/indexes - Inserting reference data
Example:
CREATE TABLE dime.users (...);Location: db/migration/repeatable/
Executed whenever file checksum changes.
Use for: - Views - Functions - Stored procedures
Example:
CREATE OR REPLACE VIEW dime.user_stats AS ...Location: db/migration/undo/
Available only in Flyway Teams but usable manually in learning mode.
Use for: - Experimenting with reversible migrations - Learning rollback strategies
All objects use the schema:
dime
Example:
CREATE TABLE dime.posts (...);- Docker & Docker Compose\
- Java 21+\
- Kotlin 2.2+
Enable commit message template:
git config commit.template .gitmessageYour commit must include:
Subject line (max 50 chars)
Files changed:(optional)
* file1
* file2
Purpose of the change: (≥50 chars)
Explain WHY.
How does it affect the application: (≥50 chars)
Explain WHAT changes.
Additional note:(optional)
PRs require: - Correct commit format\
- Targeting
develop\ - CI validation success
Branch Purpose
main Production-ready
develop Integration branch
feature/* Work branches
Replace ./gradlew with .\gradlew.bat for Windows
Start PostgreSQL:
./gradlew dbUpRun the app locally:
./gradlew bootRunStop DB:
./gradlew dbDownDestroy DB (delete data):
./gradlew dbDestroyOpen psql:
./gradlew dbShellStart everything:
./gradlew devUpStop:
./gradlew devDownDestroy:
./gradlew devDestroyGET /api/public/v1/schemas
GET /api/public/v1/tables
GET /api/public/v1/show/{name}
Example:
GET /api/public/v1/show/user_stats
./gradlew dbDestroy
./gradlew dbUp
./gradlew bootRunCreate V5__add_tags_table.sql then restart the app.
Modify a R__*.sql file → checksum change → auto re-run.
In psql:
DROP TABLE dime.comments CASCADE;
DELETE FROM flyway_schema_history WHERE version='3';curl /api/public/v1/tables?schema=dime
curl /api/public/v1/tables?schema=publicjdbc:postgresql://localhost:5432/flyway_db?currentSchema=dime
jdbc:postgresql://localhost:5433/flyway_db?currentSchema=dime
Credentials: - User: flyway_user - Pass: flyway_pass
- Always include schema names (
dime.table)\ - Never modify existing versioned migrations---create new ones\
- Use repeatables for views\
- Watch Flyway logs for details\
- Reset DB often while learning\
- Foreign keys MUST include schema name\
- Keep migrations atomic and readable
\dn -- list schemas
\dt dime.* -- list tables
SET search_path TO dime;
SELECT * FROM flyway_schema_history;CREATE TABLE dime.tags (...);ALTER TABLE dime.users ADD COLUMN bio TEXT;CREATE OR REPLACE VIEW dime.post_summary AS ...lsof -ti:5432 | xargs kill -9Recommended: - Create a new migration fixing the old one
Dev only:
DELETE FROM flyway_schema_history WHERE version='X';./gradlew dbDestroy
./gradlew clean
./gradlew dbUp- Create schema + tables\
- Insert sample data\
- Validate Flyway history\
- Query API
- Add new tables (V3, V4...)\
- Add repeatable views\
- Use full-stack mode\
- Test rollbacks
Enjoy experimenting with Flyway and contributing! Happy coding!