Understanding migrations
PocketBase has two types of migrations:- System migrations: Built into PocketBase core, these handle framework schema updates
- App migrations: User-defined migrations for your application’s collections and data
_migrations table and executed in order based on their filename.
Migration file structure
Migrations can be written in JavaScript or Go:JavaScript migrations
Located inpb_migrations/ by default:
Go migrations
Located inmigrations/ by default:
Setting up migrations
Enable migrations in your PocketBase application:Configuration options
- TemplateLang:
migratecmd.TemplateLangJSormigratecmd.TemplateLangGo(default: Go) - Automigrate: Enable automatic migration generation on collection changes (default: false)
- Dir: Custom migrations directory (default:
pb_migrations/for JS,migrations/for Go)
Creating migrations
Manual migration creation
Create a blank migration template:1234567890_add_user_bio.js:
Collections snapshot
Generate a migration with the current collections state:1234567890_collections_snapshot.js:
Automigrations
WhenAutomigrate: true is enabled, PocketBase automatically creates migrations when you modify collections through the admin UI.
For example, creating a new collection generates:
Automigrations are prefixed with action names:
created_, updated_, or deleted_.Applying migrations
Apply all pending migrations
Migration execution process
Fromcore/migrations_runner.go:122-173, the Up() method:
1
Initialize migrations table
Creates the
_migrations table if it doesn’t exist.2
Check applied status
Queries the
_migrations table to see if each migration has been applied.3
Execute in transaction
Runs unapplied migrations within a database transaction for safety.
4
Record migration
Saves the migration record with timestamp to
_migrations table.Reverting migrations
Revert last migration
Revert multiple migrations
Revert all migrations
Migration best practices
Write reversible migrations
Write reversible migrations
Always implement both
up and down functions:Use descriptive migration names
Use descriptive migration names
Good migration names describe the change:
- ✅
add_user_bio_field.js - ✅
create_comments_collection.js - ✅
migrate_old_posts_to_new_schema.js - ❌
migration1.js - ❌
update.js
Test migrations in development first
Test migrations in development first
Before applying to production:
- Create migration in development
- Test
migrate up - Verify application functionality
- Test
migrate down - Test
migrate upagain - Commit migration file
- Deploy to production
Keep migrations small and focused
Keep migrations small and focused
Create separate migrations for different changes:
Handle data migrations carefully
Handle data migrations carefully
When migrating data, handle edge cases:
Advanced migration techniques
Conditional migrations with ReapplyCondition
Fromcore/migrations_list.go:9-14, migrations support conditional reapplication:
Programmatic migration execution
Run migrations from Go code:Custom migrations table
Change the default migrations table name:Migration hooks
You can hook into migration events, though this is typically done through the migration files themselves. The migration system triggers events during execution:Troubleshooting
Migration already applied
Issue: Migration shows as applied but changes aren’t visible. Solution: Check the_migrations table:
migrate up again.
Migration file not found
Issue:_migrations table references files that don’t exist.
Solution: Sync the migrations table:
Transaction deadlock
Issue: Migration times out or deadlocks. Solution:- Ensure migrations don’t have long-running operations
- Split large data migrations into smaller batches
- Avoid external API calls in migrations
Import errors in Go migrations
Issue:undefined: Collection or similar errors.
Solution: Import the correct packages:
Next steps
Going to production
Learn production deployment best practices
Backups
Set up automated backups for your data