Neon is a serverless Postgres host with database branching, scale-to-zero, and an HTTP/WebSocket driver that runs in everyruntime DaloyJS targets, including Cloudflare Workers where raw TCP isn't available.
Two drivers, one connection string
@neondatabase/serverlessDATABASE_URLneon(...) or new Pool(...)
nodePooled Pool clientWebSocket · reused connections · pool.end()
Both clients ship in the same package. Use the lightweight HTTP neon() client on edge runtimes and the pooled WebSocket Pool for long-lived Node processes.
1. Provision
Create a project at console.neon.tech and copy the connection string. Set it as DATABASE_URL in your environment.
2. Install
ts
pnpm add @neondatabase/serverless
For a pooled connection on Node, use the Pool export. For one-shot queries on edge runtimes, use the lightweight HTTP neon()client. Neon's GA driver requires Node.js 19 or newer when you run it in Node.
3. HTTP client (edge-friendly)
ts
// src/db/neon.tsimport { neon } from "@neondatabase/serverless";import type { App } from "@daloyjs/core";export const sql = neon(process.env.DATABASE_URL!);export const neonPlugin = { name: "neon", register(app: App) { app.decorate("sql", sql); },};
4. Pooled WebSocket client (Node)
ts
// src/db/neon-pool.tsimport { Pool } from "@neondatabase/serverless";import type { App } from "@daloyjs/core";const pool = new Pool({ connectionString: process.env.DATABASE_URL! });export const neonPoolPlugin = { name: "neon-pool", async register(app: App) { app.decorate("db", pool); app.onClose(async () => { await pool.end(); }); },};
5. Augment app state
Add the declare module block to the same module that creates the clients, not to a separate .d.ts file. Declaration files are exempt from type-checking when skipLibCheck is on (the scaffolded default), so a broken import inside a .d.ts fails silently and state.sql / state.db quietly degrade to any.
ts
// src/db/neon.ts (same module as the HTTP plugin above)import type { Pool } from "@neondatabase/serverless";declare module "@daloyjs/core" { interface AppState { sql: ReturnType<typeof neon>; db: Pool; }}
6. Use it in a route
ts
import { z } from "zod";import { App, secureHeaders } from "@daloyjs/core";import { neonPlugin } from "./db/neon.ts";const app = new App();app.use(secureHeaders());app.register(neonPlugin);const UserSchema = z.object({ id: z.uuid(), email: z.email() });app.get( "/users/:id", { operationId: "getUser", request: { params: z.object({ id: z.uuid() }) }, responses: { 200: { description: "Found", body: UserSchema }, 404: { description: "Not found" }, }, }, async ({ params, state }) => { const rows = await state.sql`select id, email from users where id = ${params.id} limit 1`; const user = rows[0]; return user ? { status: 200, body: user } : { status: 404, body: { type: "about:blank", title: "Not found", status: 404 } }; },);
Cloudflare Workers
Use the HTTP neon() client and pass the connection string from the worker environment instead of process.env. Because this example reads env, wrap the Workerfetch handler and call app.fetch(req) after decorating state:
pnpm add drizzle-orm// src/db/drizzle.tsimport { drizzle } from "drizzle-orm/neon-http";import { neon } from "@neondatabase/serverless";const sql = neon(process.env.DATABASE_URL!);export const db = drizzle({ client: sql });
With Prisma
Use the Neon Driver Adapter so Prisma can run on edge runtimes (GA since Prisma 6.16.0):
ts
pnpm add @prisma/adapter-neon// src/db/prisma.tsimport { PrismaClient } from "@prisma/client";import { PrismaNeon } from "@prisma/adapter-neon";const adapter = new PrismaNeon({ connectionString: process.env.DATABASE_URL! });export const prisma = new PrismaClient({ adapter });
Use Neon's pooled connection string (host ends in -pooler) for DATABASE_URL, and a separate DIRECT_URL for Prisma CLI commands like prisma migrate and prisma db pull.
Branching for preview environments
Pair Neon's branching with Vercel preview deployments or GitHub PR previews. Create a branch per PR and pass its connection string to the deployment's DATABASE_URL. This is a natural fit for the Vercel adapter.