PostgreSQL

Fix npx prisma db push Hanging on Supabase (Port 6543)

Reproduced against Supavisor: the same schema waits until killed on port 6543 and syncs on 5432. The port, directUrl and prisma.config.ts fixes, version by version.

Mahdi Ben RhoumaMahdi Ben Rhouma
8 min read

TL;DR#

npx prisma db push prints three lines and then does nothing because the connection string points at Supabase's shared pooler on port 6543, which runs in transaction mode. The Prisma CLI needs a direct connection or the pooler's session mode on port 5432. If the project has no prisma package of its own (the question only installed @prisma/client), install it first, on the same major version as the client (prisma@6 with @prisma/client@6 for a schema like the question's): a bare npx prisma now downloads the Prisma 8 release candidate, which has no db push. Then change the port to 5432 on the same pooler host, or keep 6543 for your application and give the CLI its own 5432 URL: directUrl in schema.prisma on Prisma 5 and 6, datasource.url in prisma.config.ts on Prisma 7. Appending ?pgbouncer=true does not unblock the command.

The command that never finishes#

A Stack Overflow question describes waiting almost 30 minutes in front of this output, on a fresh project where the only commands run were npm install @prisma/client, npx prisma init and then npx prisma db push:

text
Environment variables loaded from .env
Prisma schema loaded from prisma\schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "aws-0-sa-east-1.pooler.supabase.com:6543"

No error and no timeout, and the models never reach Supabase. The asker adds that prisma migrate freezes the same way and wonders whether the models are wrong. They are not: an answer posted under the question (score 7) changed the port to 5432 because 6543 "is for Transaction pooler and you need Session pooler which is 5432". A Prisma GitHub discussion shows the identical freeze for both db push and db pull against an aws-0-eu-central-1.pooler.supabase.com:6543 URL. Its accepted answer recommends the direct connection string on port 5432 (db.[PROJECT-REF].supabase.co, user postgres), which other developers in the thread say worked for them; the asker and several others report that changing the port from 6543 to 5432 was enough.

Reproducing the freeze with Supavisor#

Supabase's shared pooler is Supavisor, which is open source. The freeze was reproduced on 5 October 2026 with the supabase/supavisor:2.9.13 Docker image (the same upstream image the Supabase CLI pins for its local pooler) in front of PostgreSQL 17.11, using the asker's schema.prisma verbatim and the postgres.<tenant> username format the shared pooler expects. Prisma 6.19.3, Node.js 22.23.3:

text
$ timeout 90 npx prisma db push
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "postgres", schema "public" at "supavisor:6543"

Nothing followed: timeout had to kill the process after 90s, with exit code 124. The same project with one change, the port in DATABASE_URL from 6543 to 5432, finished at once and created the User and News tables:

text
Datasource "db": PostgreSQL database "postgres", schema "public" at "supavisor:5432"
🚀  Your database is now in sync with your Prisma schema. Done in 118ms

The other runs of that session settle the usual suspects:

  • The schema is fine. Pointed straight at PostgreSQL with no pooler, the same schema synced normally.
  • ?pgbouncer=true is not the fix here. With it appended to the 6543 URL, db push still waited until killed.
  • db pull is affected too. Introspection through 6543 also waited until killed, matching the GitHub discussion.
  • Prisma 7 behaves the same. Prisma 7.10.0, with the URL in prisma.config.ts, waited on 6543 and synced in 100ms once the port was 5432.
  • Nothing was half-applied. While the command waited, pg_stat_activity showed the pooler's server connection idle with wait event ClientRead, its last statement a query that checks the schema exists and reads the server version: PostgreSQL was not busy and nothing was waiting on a lock. The public schema was still empty after the process was killed, so interrupting the command with Ctrl+C left the database as it was.

That stack is a local Supavisor tenant on plain PostgreSQL, reached without TLS, not Supabase's hosted pooler, whose exact version and settings cannot be inspected from outside. Session mode on the same stack worked with the same TLS fallback, so TLS was not the trigger there; the hosted side rests on the reports above and on Supabase's own documentation, below.

Why port 6543 stalls the Prisma CLI#

Supabase's connection guide spells out that the port picks the mode: on the shared pooler host, 5432 is Supavisor in session mode and 6543 is Supavisor in transaction mode. The same guide lists migrations among the jobs for a direct connection ("These are single sessions and Postgres native commands") and says transaction mode supports neither prepared statements nor query pipelining nor session state that outlives a transaction. The FAQ shipped with Supavisor 2.9.13 says it "currently supports prepared statements only in session mode".

On the Prisma side, the PgBouncer page of the Prisma 7 docs states that the schema engine behind Prisma Migrate "is designed to use a single connection to the database, and does not support connection pooling with PgBouncer", that Supavisor behaves like PgBouncer, and that CLI commands such as prisma db push and prisma db pull should use a direct connection string. Supabase's Prisma guide follows that rule: its migration URL is the session pooler string ending in 5432, and the 6543 string is only for application queries in serverless deployments.

What neither vendor documents is why the CLI waits silently instead of failing. The symptom has not always been a hang: in January 2024, a comment on Prisma issue #22779, "Migrations with Supabase Supavisor in transaction mode don't work", reported npx prisma db push against Supabase failing with prepared statement "s0" does not exist. The fix has been the same in both cases: keep the CLI off port 6543. On paid plans, db.[PROJECT-REF].supabase.co:6543 is a dedicated PgBouncer pooler that Supabase documents as transaction mode only, so it is no place for the CLI either.

Fix#

1. Install the Prisma CLI your schema expects#

The question's steps installed only @prisma/client, so npx prisma has no local CLI to run and downloads whatever npm tags as latest. As of 5 October 2026, that tag points to 8.0.0-rc.20, a release candidate of Prisma ORM 8, and the Prisma release-status page warns that this tool "does not read schema.prisma and has no generate, migrate dev, or db push commands". Run in a directory without a local prisma package, the asker's command now produces:

text
$ npx --yes prisma db push
✘ [CLI.UNKNOWN_COMMAND] No command registered for `push`, did you mean `update`?
→ List every command: prisma --help

Install the CLI and the client together, on the same major version, so that npx prisma runs the local copy. A plain npm install @prisma/client now installs 7.10.0, while the question's schema still holds its url, which only Prisma 6 and earlier accept: pin both packages to version 6 for that schema. A project configured through prisma.config.ts takes version 7, and the release-status page locks both packages to it:

bash
# schema.prisma still has url = env("DATABASE_URL"), as in the question
npm install --save-dev prisma@6
npm install @prisma/client@6
 
# or, for a Prisma 7 project configured through prisma.config.ts
npm install --save-dev prisma@7
npm install @prisma/client@7

On 5 October 2026 the two pairs resolve to 6.19.3 and 7.10.0, the versions used in the reproduction above.

2. Switch the CLI's URL to port 5432#

Copy the strings from the Connect panel of your Supabase project rather than editing hosts by hand: Supabase's guide warns that the pooler host cannot be composed from your region name. The examples in this step and the next two use an eu-west-2 host as a placeholder; what changes between them is the port.

If the same DATABASE_URL serves a long-running server, the session pooler is what Supabase's Prisma guide uses for both migrations and the application. Change only the port:

.env
bash
# before: ...pooler.supabase.com:6543/postgres
DATABASE_URL="postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-eu-west-2.pooler.supabase.com:5432/postgres"
bash
npx prisma db push

The direct connection, db.[PROJECT-REF].supabase.co:5432 with the plain postgres user, works as well, but Supabase documents it as IPv6-only unless the project has the IPv4 add-on. From an IPv4-only network the session pooler is the one that connects.

3. Prisma 5 and 6: keep 6543 for the app, add directUrl#

For serverless deployments, keep the transaction pooler for Prisma Client and give the CLI a second variable:

prisma/schema.prisma
prisma
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}
.env
bash
DATABASE_URL="postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-eu-west-2.pooler.supabase.com:6543/postgres?pgbouncer=true"
DIRECT_URL="postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-eu-west-2.pooler.supabase.com:5432/postgres"

In the reproduction, with this datasource block and DATABASE_URL still on 6543, db push printed at "supavisor:5432" in its Datasource line and synced: the CLI reads directUrl, and the application keeps the pooled URL.

4. Prisma 7: put the 5432 URL in prisma.config.ts#

Prisma 7 no longer takes connection strings from schema.prisma. The upgrade guide says a former directUrl value belongs in the url field of prisma.config.ts, because that is the URL the CLI uses:

prisma.config.ts
ts
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
 
export default defineConfig({
  schema: "prisma/schema.prisma",
  datasource: {
    url: env("DIRECT_URL"),
  },
});

Your application keeps the 6543 URL by handing it to the driver adapter. With the generator's output set to ../generated/prisma, a client module in src/ looks like this; in the reproduction, this exact module read from the database through port 6543 while the CLI used 5432:

src/db.ts
ts
import { PrismaClient } from "../generated/prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
 
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL });
export const prisma = new PrismaClient({ adapter });

A schema carried over from Prisma 6 with url = env("DATABASE_URL") still in its datasource block fails on Prisma 7.10.0 before any connection is attempted:

text
error: The datasource property `url` is no longer supported in schema files. Move connection URLs for Migrate to `prisma.config.ts` and pass either `adapter` for a direct database connection or `accelerateUrl` for Accelerate to the `PrismaClient` constructor. See https://pris.ly/d/config-datasource and https://pris.ly/d/prisma7-client-config

A leftover directUrl line in the datasource block is rejected the same way, with the same P1012 error code. For a single run without touching the config, the Prisma 7 db push reference documents --url, which overrides the configured URL; in the reproduction, npx prisma db push --url with the 5432 string synced while prisma.config.ts still pointed at 6543.

Check your own connection string#

Paste your DATABASE_URL below and tick Also used for migrations: the tool recognises a 6543 string as Supabase's transaction pooler and builds the 5432 session-mode string for the CLI. It runs entirely in your browser, and nothing you paste is sent anywhere.

Runs entirely in your browser — nothing you paste is sent anywhere, and the password is masked in every result. Still cautious? Replace the password with any string containing the same special characters: the diagnosis only needs its shape.

Verify the fix#

Run the push again and read the Datasource line before anything else: it prints the host and port the CLI actually used.

bash
npx prisma db push

A working run names port 5432 and prints the sync line, here from Prisma 7.10.0:

text
Datasource "db": PostgreSQL database "postgres", schema "public" at "supavisor:5432"
🚀  Your database is now in sync with your Prisma schema. Done in 100ms

If the Datasource line still shows 6543, the CLI is not reading the variable you edited. On Prisma 7 that usually means prisma.config.ts still points at DATABASE_URL; on Prisma 6, that directUrl is missing from the datasource block. Prisma 6 then regenerates the client on its own (the run continues with Running generate...), while the Prisma 7 db push reference notes that the command no longer runs prisma generate, so run it yourself before restarting the application.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

When the next run fails with a different message#

Adding a second variable introduces new ways to fail, and each one prints something specific. If DIRECT_URL is referenced but missing from .env, Prisma 6.19.3 stops with Environment variable not found: DIRECT_URL. and Prisma 7.10.0 with PrismaConfigEnvError: Cannot resolve environment variable: DIRECT_URL. On Prisma 7, also keep the import "dotenv/config" line at the top of the config: the upgrade guide explains that the CLI no longer loads environment variables by default. The other reasons a variable goes missing, such as a .env file in the wrong directory, are covered in Prisma: Environment variable not found: DATABASE_URL.

Once the CLI works, your application is the part still talking to port 6543. On Prisma 5 and 6, if its queries start failing with prepared statement "s0" already exists, the pooled URL is missing ?pgbouncer=true, which Supabase's Prisma troubleshooting page prescribes because transaction mode does not support prepared statements; continue with prepared statement s0 already exists: Fix for Prisma. If prisma migrate dev fails outright with FATAL: bouncer config error instead of hanging, the URL reaches a PgBouncer, as Supabase's port 6543 did in 2022, and Fix: Can't Migrate Schema Using Prisma With Supabase walks through that variant. And if Prisma rejects the edited string with invalid port number although the port is right, the usual culprit is a special character in the password breaking the URL, which Prisma Can't Connect to PostgreSQL: Fix invalid port fixes with percent-encoding.

None of this calls for a change to your models, which were never the problem in the original question. Once a CLI that matches the schema is installed, the stall comes down to where that CLI connects: a pooler built for short application transactions on port 6543, instead of the session pooler on 5432 or a direct connection.

Further reading: Fix: drizzle-kit push — statement does not return data.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote