← All posts
·5 min read
#postgres#supabase#tutorial

PostgreSQL Connection String: Supabase, Neon, Railway

Every piece of a PostgreSQL connection string, broken down, plus why Supabase's transaction pooler (port 6543) is the gotcha most tutorials skip.

The short version

A PostgreSQL connection string is a single URL that tells a client how to reach your database. It looks like this:

postgresql://postgres:[YOUR-PASSWORD]@db.abcdefghij.supabase.co:5432/postgres

Every provider builds on the same format, and the differences that trip people up are almost never the syntax. They're the port and host your provider hands you. Supabase alone has three different strings for the same database, and two of them won't work from serverless apps.

Anatomy of a connection string

postgresql://  user  :  password   @     host        :  port  /  database
     |          |         |              |              |          |
  protocol    username  secret         server        port       db name
PartExampleNotes
Protocolpostgresql://postgres:// also works
UserpostgresIn Supabase: postgres.[project-ref] on pooler URLs
Password[your-password]URL-encode special chars (@%40)
Hostdb.xxxx.supabase.coProvider-specific
Port54326543 = transaction pooler
DatabasepostgresDefault database name

You can append query parameters: ?sslmode=require (force TLS) and ?channel_binding=require.

Supabase: three strings for one database

Supabase is where most people hit the wall, because the right string depends on where your code runs:

ModeHostPortBest for
Directdb.[project-ref].supabase.co5432Migrations, pg_dump, long-lived backend
Shared pooler (session)aws-[region].pooler.supabase.com5432Persistent backend on IPv4
Shared pooler (transaction)aws-[region].pooler.supabase.com6543Serverless / edge / short-lived connections
# Direct
postgresql://postgres:[YOUR-PASSWORD]@db.[project-ref].supabase.co:5432/postgres

# Shared pooler session mode
postgres://postgres.[project-ref]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:5432/postgres

# Shared pooler transaction mode (the one most apps want)
postgres://postgres.[project-ref]:[YOUR-PASSWORD]@aws-[REGION].pooler.supabase.com:6543/postgres

The gotcha: direct connections run on IPv6. On an IPv4-only network you get ENOTFOUND, not a friendly error. The shared pooler is IPv4-only and fixes it. For serverless (Vercel, edge, Lambda) use transaction mode (port 6543).

This is why tools like dbdiagramr ask for the transaction pooler URL — otherwise the connection silently fails from IPv4-only hosts.

Neon: pooled vs direct

# Pooled (through PgBouncer, use by default)
postgresql://user:pass@ep-cool-rain-123456-pooler.us-east-2.aws.neon.tech/neondb?sslmode=require

# Direct
postgresql://user:pass@ep-cool-rain-123456.us-east-2.aws.neon.tech/neondb?sslmode=require

Rule of thumb: use the -pooler host unless you have a specific reason not to. Grab both from the Connect button in the Neon dashboard.

Railway: the plain standard

postgresql://postgres:[YOUR-PASSWORD]@[host].railway.app:5432/railway

No pooler decision — textbook format, easiest to read and to misplace a password in. Store in DATABASE_URL, never in code.

All the formats in one table

ProviderConnection string shape
Standard / Railwaypostgresql://user:pass@host:5432/db
Supabase (direct)postgresql://postgres:pass@db.[ref].supabase.co:5432/postgres
Supabase (session)postgres://postgres.[ref]:pass@aws-[region].pooler.supabase.com:5432/postgres
Supabase (transaction)postgres://postgres.[ref]:pass@aws-[region].pooler.supabase.com:6543/postgres
Neon (pooled)postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/db?sslmode=require
Neon (direct)postgresql://user:pass@ep-xxx.region.aws.neon.tech/db?sslmode=require

Gotchas that will actually bite you

  • IPv4 vs IPv6. Supabase direct is IPv6. IPv4-only hosts get ENOTFOUND. The pooler strings are IPv4 and sidestep it.
  • Serverless wants the transaction pooler. Long-lived backends can hold a connection; serverless functions open one per invocation. Session pooling chokes; transaction pooling (port 6543) exists for it.
  • A connection string is a secret. Password in plain text. Never commit it, never paste into a shared doc. Most good tools never store it beyond one request.
  • URL-encode passwords. A password with @, :, or / breaks the URL. Encode those.

Curious what that pooler URL contains after it connects? The Supabase auth schema diagram was created by introspecting a live Supabase database through a transaction pooler string.

FAQ

What is a PostgreSQL connection string?
A single URL with everything needed to reach a Postgres database: protocol, username, password, host, port, and database name.

Should I use a direct connection or a pooler?
Persistent backend → direct is fine. Serverless/edge → use a pooler (Supabase transaction mode port 6543 or Neon -pooler host).

Why does my Supabase connection fail with ENOTFOUND?
You're using the direct string over IPv4, and Supabase's direct endpoint is IPv6. Switch to a shared pooler string.

Is my connection string a secret?
Yes — password in plain text. Keep in environment variables, rotate if leaked, only hand to tools that won't store it.

Visualize your own database

Paste your PostgreSQL connection string and get an interactive ER diagram in under 10 seconds. No signup required.