Run Database Migrations
Use lifecycle hooks to run Alembic, Prisma, Django, or Drizzle migrations on every deploy
Database migrations update your database schema — adding tables, columns, indexes, and more — as your application evolves. Hostess can run migration commands before each deployment using lifecycle hooks, so schema changes can move with your application code.
How It Works
init and shutdown run inside your service container — init before the main process starts, shutdown before it is terminated.
migrate and post_deploy run as separate background processes. They are submitted before your new service version is rolled out, but do not block the rollout — your service may start before they complete.
| Hook | Where | When |
|---|---|---|
init | Inside your service container | Before the main process starts |
migrate | Separate background process | Submitted before rollout; runs concurrently |
post_deploy | Separate background process | Submitted before rollout; runs concurrently |
shutdown | Inside your service container | Before the process is terminated |
Because migrate runs concurrently with your service rollout, write migrations to be backward-compatible — both the old and new versions of your code should tolerate the schema during the transition.
Framework-Specific Configuration
Alembic is the standard migration tool for SQLAlchemy-based Python applications (FastAPI, Flask, etc.).
version: "1.0"
services:
database:
type: postgres
resources: medium
api:
type: fastapi
build:
source: ./backend
depends_on:
- database
env:
DATABASE_URL: ${database.url}
lifecycle:
migrate:
command: ["alembic", "upgrade", "head"]
timeout: 10mHow it works:
alembic upgrade headapplies all pending migration files from youralembic/versions/directory- The
DATABASE_URLenvironment variable is automatically available to the migration job - The migration runs from your application's build context, so your
alembic.iniand migration files are included
Creating new migrations locally:
# Generate a new migration based on model changes
alembic revision --autogenerate -m "add users table"
# Review the generated migration file in alembic/versions/
# Commit and deploy — Hostess runs it automaticallyTimeout Configuration
Migrations have a default timeout of 5 minutes. For large databases or complex migrations, increase the timeout:
lifecycle:
migrate:
command: ["alembic", "upgrade", "head"]
timeout: 10m # 10 minutesSupported time formats:
30s— 30 seconds5m— 5 minutes (default)10m— 10 minutes1h— 1 hour
If the migration exceeds the timeout, the migration job exceeds its active deadline and is treated as failed.
Combining Lifecycle Hooks
You can use multiple lifecycle hooks together. They execute in order:
services:
web:
type: custom
build:
source: .
depends_on:
- database
env:
DATABASE_URL: ${database.url}
lifecycle:
init:
command: ["python", "manage.py", "collectstatic", "--noinput"]
migrate:
command: ["python", "manage.py", "migrate", "--noinput"]
timeout: 10m
post_deploy:
command: ["python", "scripts/warmup_cache.py"]
shutdown:
timeout: 30s
command: ["python", "scripts/cleanup.py"]Execution order:
initruns inside your service container before the main process starts (collect static files)migrateandpost_deployare submitted as background processes before the rollout — they run concurrently with the service startingshutdownruns inside your service container when it is being terminated
Best Practices
Write reversible migrations
Whenever possible, write migrations that can be rolled back. Most migration tools support "down" migrations:
- Alembic:
alembic downgrade -1 - Prisma: Prisma doesn't support down migrations natively — test thoroughly before deploying
- Django:
python manage.py migrate app_name 0003_previous_migration - Drizzle:
npx drizzle-kit drop
Test migrations on a preview environment first
Before running a migration in production, deploy to a preview or staging environment:
# Deploy to staging first
hostess deploy --env staging
# Verify the migration succeeded, then deploy to production
hostess deploy --env productionAvoid long-running migrations in a single step
Large data migrations (e.g., backfilling millions of rows) can time out. Break them into smaller steps:
- Schema migration: Add the new column (fast, runs during deploy)
- Data migration: Backfill data in batches using a post-deploy script or background job
- Cleanup migration: Remove the old column once backfill is complete
Keep migration files in version control
Always commit your migration files alongside the code that uses the new schema. This ensures that:
- Migrations are reviewed in pull requests
- Every deployment has the correct set of migrations
- You can track schema changes over time