<!-- section: Data API · status: building · source: docs/data-api/03-connect.md -->

> Two connection strings, which one to use, and the settings that matter.


# Connecting

You get two connection strings. They reach the same database.

```
postgresql://booking_owner:…@ep-little-morning-b130w8eo-pooler.c-5.eu-central-1.aws.neon.tech/booking?sslmode=require&channel_binding=require
postgresql://booking_owner:…@ep-little-morning-b130w8eo.c-5.eu-central-1.aws.neon.tech/booking?sslmode=require&channel_binding=require
```

| | Use it for |
|---|---|
| **Pooled** (`-pooler`) | Your application. Anything serverless, edge, or with many short-lived connections |
| **Direct** | Migrations, `psql`, and anything holding one long connection |

## Why two

Postgres allocates a process per connection, and a small compute allows a few
hundred. A serverless application opens one per invocation, so a traffic spike
becomes `too many clients already` at exactly the moment you least want it.

The pooled endpoint puts PgBouncer in front, so thousands of client connections
share a few real ones. The cost is that it is in transaction pooling mode:
session-level state does not survive between statements. In practice that means
`LISTEN`/`NOTIFY`, advisory locks held across statements, and some migration
tools do not work through it — which is what the direct endpoint is for.

**Use pooled unless something breaks.** Then use direct for that one thing.

## Examples

```js node-postgres
import { Pool } from "pg";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const { rows } = await pool.query("select now()");
```

```js postgres.js
import postgres from "postgres";

const sql = postgres(process.env.DATABASE_URL);
const rows = await sql`select now()`;
```

```bash psql
psql "$DATABASE_URL_DIRECT"
```

Any Postgres client works — this is not an API of ours with a driver to learn.
Prisma, Drizzle, Sequelize, SQLAlchemy, ActiveRecord and `psql` all connect to it
the way they connect to any Postgres.

On a runtime with no TCP sockets — Cloudflare Workers, some edge functions — use
a driver that speaks Postgres over HTTP. `@neondatabase/serverless` is the one
that matches the host below, and it takes the same connection string.

## Who runs the machine

The hostname says `neon.tech`, and rather than dress that up: **the Postgres
underneath is Neon**, resold by us. We create it, set its limits, meter it and
put it on your bill; they run the hardware. It is listed among our
[subprocessors](/privacy) with everyone else.

Worth knowing because of what it means for you rather than for us:

- **It is not a fork.** Standard Postgres 18, standard extensions, standard wire
  protocol. Nothing here is a dialect you would have to unlearn.
- **You can leave.** `pg_dump` against the direct string is a complete copy, and
  it restores into any Postgres anywhere. Nothing about this is a lock-in
  designed to be hard to undo.
- **Your account is with us.** One invoice, one support conversation, one place
  that owes you an answer when a query is slow.

## TLS is not optional

Both strings carry `sslmode=require` and `channel_binding=require`, and the
server refuses anything less. Do not strip them. A client that cannot do channel
binding can drop that parameter; `sslmode` stays.

## Keep it in an environment variable

The string contains a password. It belongs in your platform's secret store, not
in a repository, and it is worth reading
[replacing the password](/docs/data-api/credentials) before the first time
somebody pastes it into a chat window.
