H
Hostess

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.

HookWhereWhen
initInside your service containerBefore the main process starts
migrateSeparate background processSubmitted before rollout; runs concurrently
post_deploySeparate background processSubmitted before rollout; runs concurrently
shutdownInside your service containerBefore 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.).

hostess.yml
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: 10m

How it works:

  • alembic upgrade head applies all pending migration files from your alembic/versions/ directory
  • The DATABASE_URL environment variable is automatically available to the migration job
  • The migration runs from your application's build context, so your alembic.ini and migration files are included

Creating new migrations locally:

Terminal
# 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 automatically

Timeout Configuration

Migrations have a default timeout of 5 minutes. For large databases or complex migrations, increase the timeout:

hostess.yml
lifecycle:
  migrate:
    command: ["alembic", "upgrade", "head"]
    timeout: 10m  # 10 minutes

Supported time formats:

  • 30s — 30 seconds
  • 5m — 5 minutes (default)
  • 10m — 10 minutes
  • 1h — 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:

hostess.yml
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:

  1. init runs inside your service container before the main process starts (collect static files)
  2. migrate and post_deploy are submitted as background processes before the rollout — they run concurrently with the service starting
  3. shutdown runs 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:

Terminal
# Deploy to staging first
hostess deploy --env staging

# Verify the migration succeeded, then deploy to production
hostess deploy --env production

Avoid long-running migrations in a single step

Large data migrations (e.g., backfilling millions of rows) can time out. Break them into smaller steps:

  1. Schema migration: Add the new column (fast, runs during deploy)
  2. Data migration: Backfill data in batches using a post-deploy script or background job
  3. 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

On this page