Schema migrations

Schema changes have exactly one paved path: declare a migration command per database in fluffy-chainsaw.yaml, keep your migration files in the repo, and let fluffy-chainsaw migrate run them — locally and deployed — as a dedicated migrator identity that the app's runner identity never holds.

databases:
  posts:
    instance: serving-db
    migrations:
      run: npx node-pg-migrate -m migrations up

What declaring migrations changes

Identity Without migrations With migrations
Runner (serves traffic) CONNECT, CREATE, TEMPORARY on the db CONNECT, TEMPORARY + DML on tables (no DDL)
Migrator (fluffy-chainsaw migrate only) owns the schema: CREATE on db + schema, runs your tool

After each run, fluffy-chainsaw migrate also grant-syncs: as the migrator it grants SELECT/INSERT/UPDATE/DELETE on all tables (and sequence usage) to every runner that uses the database, and sets default privileges so the next migration's tables are granted automatically. A runner added later gets its grants on the next deploy — fluffy-chainsaw deploy always runs migrate after provision.

Running

# local — against the fluffy-chainsaw local postgres (the m_<db> role):
fluffy-chainsaw local            # full and --deps-only modes migrate automatically before anything reads the db
fluffy-chainsaw migrate --local  # re-run by hand after adding a migration

# deployed — against the Cloud SQL database, no password anywhere:
fluffy-chainsaw deploy           # build -> provision -> migrate -> firebase
fluffy-chainsaw migrate          # just the migrate stage (reads the stack's `migrations` output)

Deployed, fluffy-chainsaw migrate impersonates the database's migrator service account (dbmig-<db>) through a cloud-sql-proxy it starts for you with IAM auth — your own gcloud identity must be allowed to impersonate it, which the stack grants to its deployerPrincipal. Install the proxy once: brew install cloud-sql-proxy.

Rules and edges

Deploy ordering and boot rules

During deployment (fluffy-chainsaw deploy), the stages run in the following sequence: buildscanprovisionmigratefirebase (hosting rewrites).

Because Pulumi provisions both the Cloud SQL database and the Cloud Run service in the same pulumi up call (the provision stage), the application container will boot and execute its startup checks before the migrations have run (the migrate stage).

To prevent deployment rollbacks due to missing tables or temporary permission lags:

Example

The auth example is the reference: examples/auth/app/migrations/ holds the schema, databases.posts.migrations.run points node-pg-migrate at it, and the server contains no DDL.