Database Migrations
Last updated: February 13, 2026
This guide covers Sophie Bot's database migration system using Beanie ODM.
Overview
Sophie uses Beanie's built-in migration system to manage database schema evolution.
Migrations are versioned, reversible Python scripts that transform data between schema versions.
How It Works
- Migration files are stored in sophie_bot/db/migrations/
- Each migration has a timestamp prefix: YYYYMMDD_HHMMSS_description.py
- Migrations define ForwardandBackwardclasses for apply/rollback
- Applied migrations are tracked in the migration_statescollection
- Migrations run automatically on startup for beta instance
Creating a Migration
Quick Start
This creates a file like:
sophie_bot/db/migrations/20240125_120000_add_user_preferences.py
Manual Creation
- Create file: sophie_bot/db/migrations/20240125_120000_add_user_preferences.py
- Define old and new model structures if needed
- Implement Forward and Backward migration classes
- Test migration locally
- Add tests to tests/test_migrations.py
Migration Examples
Example 1: Add New Field
Example 2: Rename Field
Example 3: Convert Data Type
Example 4: Bulk Migration with Free Fall
Migration Types
Iterative Migration
When to use:
- Most document transformations
- When you need to transform data field-by-field
- Simple field additions, renames, or type conversions
Pros:
- Beanie handles document loading and saving
- Memory efficient (processes one document at a time)
- Can be resumed if interrupted
- Good for large collections
Cons:
- Limited control over database session
- Can be slower for bulk operations
- Hard to track progress
Free Fall Migration
When to use:
- Bulk operations (rebuilding indexes, collections)
- When you need full database control
- Complex transformations requiring multiple collections
- Performance-critical operations
Pros:
- Full control over database session
- Can use batch processing
- Better performance for bulk operations
- Can track progress manually
Cons:
- More complex to implement
- Must handle document loading/saving manually
- Risk of memory issues with large collections
Running Migrations
Automatic (Recommended for Beta)
Migrations run automatically on startup when
instance_name=beta
:Manual
Run all pending migrations:
Or using Python directly:
Check Status
Example output:
Rollback
Rollback a specific migration:
Or using Python:
Configuration
Configure migrations in
config.py
:Transaction Support
MongoDB transactions provide atomicity for migrations, ensuring either all changes succeed or none do.
Enabling Transactions
- Configure MongoDB replica set (required for transactions)
- Enable replica set in config:
When to Use Transactions
Use transactions for:
- Multi-collection migrations
- Critical data transformations
- Rollback safety is essential
- Collections with relational dependencies
Avoid transactions for:
- Very large collections (millions of documents)
- Simple field additions
- Non-critical migrations
- When replica set is not available
Transaction Limitations
MongoDB transactions have limits:
- Document size: 16MB per document
- Transaction size: 16MB total
- Operation count: Varies by MongoDB version
- Execution time: 60 seconds default
For large collections, use free fall migration without transactions.
Handling Large Collections
Batching Strategy
For collections with millions of documents, implement batching:
Progress Monitoring
Add progress logging for long-running migrations:
Performance Tips
- Use appropriate batch size: 1000-10000 typically works well
- Create indexes before migration: Improves query performance
- Drop indexes before bulk inserts: Faster for large insertions
- Monitor memory usage: Adjust batch size if memory issues occur
- Run during maintenance: Reduces impact on users
Testing
Running Tests
Or:
Writing Tests
Add tests to
tests/test_migrations.py
:Deployment Workflow
- Create migration on development branch
- Test locally: make migrate_up
- Add tests to tests/test_migrations.py
- Test in staging (beta instance)
- Verify status: make migrate_status
- Open merge request with migration details
- CI runs tests automatically
- Merge to main/beta
- Deploy to beta - migrations run automatically
- Verify in beta
- Deploy to stable if needed
Troubleshooting
Migration Failed Mid-Execution
Symptoms:
- Migration error in logs
- Some documents migrated, some not
- Migration state may or may not be recorded
Solutions:
- Check logs for specific error details
- Manually fix affected documents if needed
- Re-run migration - it will skip already-applied steps
- Consider rolling back if state is inconsistent
Migration Too Slow
Symptoms:
- Migration taking hours to complete
- High CPU/memory usage
- Database slow to respond
Solutions:
- Use @free_fall_migration()for better control
- Implement batching with migration_batch_size
- Create appropriate indexes before migration
- Consider running during maintenance window
- Monitor and optimize database performance
Need to Roll Back
Procedure:
- Stop application to prevent conflicts
- Identify migration to rollback:
- Run rollback:
- Verify rollback with status check
- Fix migration code if issue was in migration
- Re-apply migration if needed
Important:
- Rollbacks modify data - test in staging first
- Rollbacks may take time for large collections
- Monitor logs during rollback
- Have data backup if possible
Transaction Errors
Symptoms:
- Transaction numbers do not matcherror
- Transaction is not in progresserror
- Migration fails with transaction-related error
Solutions:
- Check MongoDB is running as replica set
- Verify mongo_use_replica_set = Truein config
- Disable transactions for large collections:
- Use free fall migration instead
Best Practices
Before Creating Migration
- Document migration purpose and expected changes
- Identify affected models and collections
- Estimate document count for affected collections
- Plan both Forward and Backward logic
- Consider impact on running application
- Add tests for migration
- Update documentation
- Get code review
Before Deploying to Production
- Verify migration passed in CI
- Test in staging environment
- Confirm data integrity after migration
- Document rollback procedure
- Notify team of deployment window
- Monitor logs after deployment
- Verify application functionality
Common Pitfalls
â Don't:
- Create migrations without backward classes
- Skip testing migrations
- Run migrations on production without testing
- Use broad exception handlers that hide errors
- Forget to document migration impact
- Run migrations on stable instance (use beta only)
â
Do:
- Implement both Forward and Backward classes
- Test migrations thoroughly in staging
- Use descriptive migration names
- Handle large collections with batching
- Monitor migration progress with logs
- Document rollback procedures
References
Migration Checklist
Pre-Migration:
- Migration file created with proper naming
- Forward and Backward classes implemented
- Docstring with description and impact
- Tests written in tests/test_migrations.py
- Code reviewed by team
- Tested locally with make migrate_up
- Tested in staging environment
Post-Migration:
- Migration applied successfully
- Data integrity verified
- Application functionality tested
- Performance acceptable
- Logs reviewed for errors
- Documentation updated
- Rollback procedure documented
Production Deployment:
- Staging migration successful
- Rollback procedure documented
- Team notified of deployment
- Maintenance window scheduled (if needed)
- Monitoring configured
- Backup taken (if possible)