---
name: postgres-nextjs
description: "Provisions a Postgres database (a Neon project of its own) for a Next.js app with `npx extraorbital add postgres` (no signup, no card) and wires it into Next.js with `@neondatabase/serverless`. Use when a Next.js project needs Postgres, PostgreSQL, a SQL database, Neon, POSTGRES_URL, Prisma or Drizzle, or when POSTGRES_URL is missing or unset in .env."
---

# Postgres in Next.js

<!-- Generated from ExtraOrbital's service registry by `pnpm skills:build` in platform/app. Edit the generator, not this file. -->

ExtraOrbital provisions a Postgres database (a Neon project of its own) in one command and writes the credentials into the project's env file. For anything this recipe does not cover, use the `extraorbital` skill or https://extraorbital.dev/llms.txt.

## 1. Provision

```bash
npx extraorbital add postgres
```

Run it from the project root. It is idempotent (a second run returns the same resource) and writes to `.env.local` if the project has one, otherwise `.env`, keeping that file out of git. Add `--json` to parse the result; credential values are redacted there, and you should never print them either.

| Variable | |
| --- | --- |
| `POSTGRES_URL` | Pooled: use it in the app |
| `POSTGRES_URL_NON_POOLING` | Direct: migrations, and anything that needs a session |
| `POSTGRES_HOST` |  |
| `POSTGRES_USER` |  |
| `POSTGRES_PASSWORD` |  |
| `POSTGRES_DATABASE` |  |

Free on the Prototype plan: 1 database, from the $5.00 account allowance.

## 2. Install the client

```bash
npm install @neondatabase/serverless
```

## 3. Connect

Next.js loads both `.env.local` and `.env`, so either file ExtraOrbital writes is read on the next `next dev`.

**`lib/postgres.ts`**

```ts
import { neon } from "@neondatabase/serverless";

// Queries over HTTP: no pool to keep alive, so it is safe to create at module scope anywhere.
export const sql = neon(process.env.POSTGRES_URL!);
```

## 4. Use it

**`app/api/postgres/route.ts`**

```ts
import { sql } from "@/lib/postgres";

export async function GET() {
  const rows = await sql`select now() as now`;
  return Response.json({ now: rows[0]?.now });
}
```

## 5. Verify

```bash
npx extraorbital list        # the resource is listed as active
npm run dev
curl http://localhost:3000/api/postgres
```

A JSON answer means the credentials, the client and the route all work. Delete the route afterwards if the app does not need it.

## Pitfalls

- Point migration tools at `POSTGRES_URL_NON_POOLING` (Prisma's direct URL, `drizzle-kit`, Alembic, `manage.py migrate`); through the pooler they fail in confusing ways.
- Not `DATABASE_URL`: ExtraOrbital never claims that name. If the code already reads it, change the code or copy the value of `POSTGRES_URL` into it yourself.
- Any Postgres client works with the same URL (`pg`, `postgres`, Prisma, Drizzle, Kysely); a long-lived server can use `pg.Pool` instead.
- Scale-to-zero: the first query after five idle minutes takes a moment longer. Storage still bills while idle, from the account allowance on Prototype.
- Import the module only from server code (route handlers, server components, server actions). Only `NEXT_PUBLIC_*` variables reach the browser, and nothing else should.
- With a `src/` directory the module goes in `src/lib/`; without the `@/*` path alias, import it relatively.
- Restart `next dev` after the env file changes: it is read at startup.
- Exit code 3 means the account is past its free allowance: show the human the link the command printed and wait. Do not retry or work around it.

Docs: https://extraorbital.dev/docs/resources/neon.md
