# Neon on AWS Lambda: reuse the client, use the pooled string
## The trap
The naive Lambda pattern connects inside the handler on every invocation. With 100 concurrent invocations you hold 100 Postgres connections, and on a small Neon compute that is the whole `max_connections` budget gone. The function then fails with "too many clients already" exactly when traffic is highest.
## The rule
1. Create the client (or pool) at module scope, outside the handler, so warm invocations reuse it. Connect lazily on first use.
2. Point it at the pooled connection string (`-pooler` hostname). PgBouncer absorbs the per-invocation churn.
3. Always close or handle errors so a dead client does not poison the warm container; recreate on failure.
```js
const { Client } = require('pg');
let client;
async function getClient() {
if (!client) {
client = new Client({ connectionString: process.env.DATABASE_URL });
await client.connect();
}
return client;
}
exports.handler = async () => {
const c = await getClient();
const { rows } = await c.query('SELECT * FROM users');
return { statusCode: 200, body: JSON.stringify(rows) };
};
```
## Checklist
- Client created once per execution environment, not per invocation.
- `DATABASE_URL` is the pooled string.
- On connection errors, drop the cached client so the next invocation reconnects.
- If you use provisioned concurrency or VPC, recheck: VPC Lambda needs NAT to reach Neon, and each provisioned instance holds its own client.