Migrations on Docker boot
What changed
The container now applies pending Drizzle migrations to the libSQL database on startup, so a fresh deploy (or a reset database) no longer needs a manual pnpm db:migrate from the host. docker-setup.md already claimed "first boot runs migrations" — this makes that true.
packages/db/server/utils/run-migrations.ts—runMigrations(folder)wrapsdrizzle-orm/libsql/migratorusing the sharedtursoClient.packages/site/server/plugins/db-migrate.ts— Nitro startup plugin, gated byDB_MIGRATE_ON_BOOT=1, with a bounded retry and fail-fast on error.Dockerfile(runtime stage) — copiespackages/db/db/migrationsto.output/migrationsand setsDRIZZLE_MIGRATIONS_DIR.docker-compose.yml— setsDB_MIGRATE_ON_BOOT=1on thesiteservice.
Why gated + fail-fast
- Gated on
DB_MIGRATE_ON_BOOT=1. The Docker build runspnpm sitewhich boots Nitro for prerender; at that pointNUXT_TURSO_DATABASE_URLis unset and the config falls back tofile:../../local.db. Without the gate the build would migrate a throwaway file.import.meta.prerenderis a second guard. - Retry (15 × 2s). The compose
dbservice has no healthcheck, so a fresh boot can race the database. - Fail-fast. A migration failure throws, Nitro startup fails, the container exits, and
restart: unless-stoppedloops with the error indocker compose logs site. A half-migrated schema is never served.
How it works
Node (node .output/server/index.mjs) resolves drizzle-orm from .output/server/node_modules; the plugin is bundled by Nitro, so the HTTP libSQL client works at boot. migrate() is idempotent — applied migrations are recorded in __drizzle_migrations and skipped on the next boot.
Gotchas
- Single
sitereplica assumption. Multiple replicas would race the migrator and need the one-shotmigrateservice variant instead. - The published image (
ghcr.io/leamsigc/magicsync) needs a rebuild for the DockerfileCOPYto take effect. DB_MIGRATE_ON_BOOTin a host.envalso makespnpm site:devmigrate on boot againstNUXT_TURSO_DATABASE_URL; it is left commented in.env-example.
Verify
bash
docker compose up -d --build
docker compose logs -f site # "[db-migrate] migrations applied from ..."
docker compose restart site # second boot: no-op
# break it: DRIZZLE_MIGRATIONS_DIR=/nope -> container exits with the error