Search docs

Jump between documentation pages.

Use Neon serverless Postgres with DaloyJS

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 and Vercel Edge where raw TCP isn't available.

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.ts
import { 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.ts
import { 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

ts
// src/types/state.d.ts
import type { Pool } from "@neondatabase/serverless";
import type { neon } 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";

const app = new App();
app.use(secureHeaders());
app.register(neonPlugin);

const UserSchema = z.object({ id: z.string().uuid(), email: z.string().email() });

app.route({
  method: "GET",
  path: "/users/:id",
  operationId: "getUser",
  request: { params: z.object({ id: z.string().uuid() }) },
  responses: {
    200: { description: "Found", body: UserSchema },
    404: { description: "Not found" },
  },
  handler: 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:

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

export default {
  async fetch(req: Request, env: { DATABASE_URL: string }) {
    const sql = neon(env.DATABASE_URL);
    app.decorate("sql", sql);
    return app.fetch(req);
  },
};

With Drizzle ORM

ts
pnpm add drizzle-orm
// src/db/drizzle.ts
import { 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.ts
import { 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.

See also PlanetScale, Supabase, and the database hosting overview.