Deployment

Fly Database Migrations

Running database migrations on deploy

When to use this page

  • You need schema migrations to run automatically during Fly deployments.
  • You want deployment to stop safely when migrations fail.

Prerequisites

  • Application already deployable on Fly.
  • Migration command/script available in your project.
  • Dockerfile supports custom entrypoint.

When deploying to Fly.io, migrations should run before new instances serve traffic. Fly handles this with release commands executed after build and before rollout.

Step 1: Create entrypoint script

We recommend using a single entrypoint.sh that accepts a command argument. This way the same script serves as both the server start command and the migration runner:

#!/bin/sh
set -e

COMMAND="${1:-server}"

if [ "$COMMAND" = "server" ]; then
  echo "Starting server..."
  node --max-old-space-size=1024 ./main.js
elif [ "$COMMAND" = "migrate" ]; then
  echo "Running migrations..."
  node ./drizzle-migrate.js
else
  echo "Usage: entrypoint.sh [server|migrate]"
  exit 1
fi

Drizzle migration script

For a ready-to-use Drizzle migration script, check out drizzle-migrate.ts from our boilerplate.

Make sure the script is executable:

chmod +x entrypoint.sh

Step 2: Add script to Dockerfile

Ensure the entrypoint script is copied into your Docker image and set it as the ENTRYPOINT:

COPY entrypoint.sh /app/entrypoint.sh
ENTRYPOINT [ "./entrypoint.sh" ]

Since the entrypoint defaults to server, your app will start normally. The migrate argument is only passed by the release command during deploys.

Step 3: Configure fly.toml

Add the migration as a release command:

[deploy]
  release_command = "migrate"

Because ENTRYPOINT is set in the Dockerfile, Fly passes migrate as the argument to entrypoint.sh, which triggers the migration branch of the script.

Release command failures

If the release command fails (non-zero exit code), the deployment is halted and the previous version of your app continues running. Check the output with fly logs to debug migration issues.

How it works

  1. You run fly deploy
  2. Fly builds your Docker image
  3. Fly creates a temporary Machine and runs the release command (your migration script)
  4. If the migration succeeds, Fly rolls out the new Machines
  5. If the migration fails, the deploy is aborted

Verify

  • Deploy output shows release command executed successfully.
  • New app version starts only after migration success.
  • Database schema version matches expected migration state.

Troubleshooting

  • release_command not running: Confirm [deploy] release_command = "migrate" exists in fly.toml.
  • Script permission denied: Ensure chmod +x entrypoint.sh is executed before image build.
  • Deploy blocked by migration error: Inspect release logs with fly logs and fix migration script idempotency issues.

On this page