One Failed Migration Bricked Every Deploy After It
Prisma takes an advisory lock before migrating. Run that through a connection pooler and a failed migration can leave the lock held by a session nobody can reach.
What
Prisma takes a Postgres advisory lock before running migrations so two deploys cannot migrate at the same time. Cantrip pointed migrations at Neon's pooled connection string, which is the one in every example. When a migration errored, the pooled session holding that lock was recycled instead of closed, and the lock stayed held by a backend nothing could address. Every deploy afterwards failed to acquire it. Three production deploys in a row failed for a reason that had nothing to do with the code being deployed.
The decision that mattered
Run migrations against the direct endpoint and leave the pooler to the application. Pooling is what makes serverless database access work, and it is also what makes a stranded lock unrecoverable, because you cannot reliably reach the session still holding it.
The direct endpoint does not wake a suspended compute the way the pooler does, so the first deploy after an idle period fails to connect instead. Fixing one failure mode exposed another. The deploy script now warms the compute through the pooler before migrating direct, which is two connection strings doing two different jobs on purpose.
Good / Bad / Ugly
Migrations run against the direct endpoint, so a stranded advisory lock is no longer a reachable failure mode.
It took three failed production deploys to work out that the failure had nothing to do with the migration being applied.
The fix introduced a second trap. The direct endpoint will not wake a sleeping Neon compute, so the first deploy after an idle window failed with a different error entirely. That one could only show up in production, because local development never runs the deploy path.
Shipped
A deploy script that strips the pooler from the connection string and warms the compute first, wired into the Vercel prebuild.
Next
Reconcile the dev branch's migration history, which has drifted far enough that the normal migrate command is unusable there.