Migrations
Migrations describe database schema changes as ordered files.
Generated GoForj Apps include migration commands when database support is enabled.
Commands
Run pending migrations:
forj migrateRun migrations for a named app with the app prefix:
forj billing migrateGenerate a migration:
forj make:migration create_usersRun this from the generated App root. Migration generation is a project-level forj command, while applying and rolling back migrations happens through the generated App command surface.
Remove generated migration files that match a migration name:
forj make:migration create_users --removeThe removal command matches timestamped files by migration name, including driver-specific files such as .sqlite.up.sql and .postgres.down.sql. Use --connection analytics when removing migration files from a named connection directory.
Rollback recent migrations:
forj migrate:rollbackFor a named app:
forj billing migrate:rollbackThe generated migration command supports options such as step count, dry run, and connection selection.
Files
Migration files live under:
migrations/Driver-specific migrations include the driver name:
migrations/2026_01_01_000001_create_users.sqlite.up.sql
migrations/2026_01_01_000001_create_users.sqlite.down.sql
migrations/2026_01_01_000001_create_users.postgres.up.sql
migrations/2026_01_01_000001_create_users.postgres.down.sqlNamed Connections
Root migration files target the default connection.
Subdirectories target named connections:
migrations/analytics/2026_01_01_000001_add_events.postgres.up.sql
migrations/analytics/2026_01_01_000001_add_events.postgres.down.sqlThe analytics directory maps to DB_ANALYTICS_*.
Multi-App Projects
When a Project has multiple apps, migrations are grouped by app first and connection second:
migrations/app/default/
migrations/billing/default/
migrations/billing/analytics/This keeps each app's schema changes easy to review while preserving named connection ownership.
Migration Table
Each connection maintains its own migration table in that database.
This lets default and named connections migrate independently.
Safe Migration Practice
Prefer migrations that are:
- explicit
- reversible when practical
- small enough to review
- driver-specific when SQL differs by backend
- run through the App command path
Use dry run before applying migrations when you need visibility:
forj migrate --dry-runCommon Mistakes
Common mistakes
- Do not assume one SQL file works for every driver.
- Do not put named-connection migrations in the root directory.
- Do not manually edit migration history unless you are intentionally repairing a database.
- Do not run migrations outside the App path when the generated command owns connection selection.
- Do not forget that each connection has its own migration table.
- Do not mix named app migrations into another app's migration directory.
Next Steps
- Database Strategy explains connection configuration.
- Repositories explains where query code should live.
- Testing Overview explains generated App testing direction.