Astro
Astro connects to DB9 through any standard PostgreSQL driver when running in SSR mode. DB9 is PostgreSQL-compatible, so no special adapter or driver is needed.
Prerequisites
Section titled “Prerequisites”- A DB9 database (create one)
- Node.js 18+
- Astro 4+
Create a DB9 Database
Section titled “Create a DB9 Database”db9 create --name astro-appGet the connection string:
db9 db status astro-appSet the connection string as an environment variable:
DATABASE_URL="postgresql://astro-app.admin:YOUR_PASSWORD@pg.db9.io:5433/postgres?sslmode=require"Enable SSR
Section titled “Enable SSR”Astro defaults to static output, which cannot connect to a database at request time. Switch to server-rendered mode and add the Node adapter:
npx astro add nodeThen set output: 'server' in your config:
import { defineConfig } from 'astro/config';import node from '@astrojs/node';
export default defineConfig({ output: 'server', adapter: node({ mode: 'standalone', }),});Install
Section titled “Install”npm install prisma @prisma/clientnpx prisma initSchema
Section titled “Schema”generator client { provider = "prisma-client-js"}
datasource db { provider = "postgresql" url = env("DATABASE_URL")}
model User { id Int @id @default(autoincrement()) email String @unique name String createdAt DateTime @default(now())}Push the schema and generate the client:
npx prisma db pushnpx prisma generateSingleton client
Section titled “Singleton client”import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (import.meta.env.DEV) { globalForPrisma.prisma = prisma;}Install
Section titled “Install”npm install drizzle-orm pgnpm install -D drizzle-kit @types/pgSchema
Section titled “Schema”import { pgTable, serial, varchar, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', { id: serial('id').primaryKey(), email: varchar('email', { length: 255 }).unique().notNull(), name: varchar('name', { length: 100 }).notNull(), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),});Client
Section titled “Client”import { drizzle } from 'drizzle-orm/node-postgres';import { Pool } from 'pg';
const pool = new Pool({ connectionString: import.meta.env.DATABASE_URL,});
export const db = drizzle(pool);Server Endpoint
Section titled “Server Endpoint”Create an API route that handles GET and POST requests:
import type { APIRoute } from 'astro';import { prisma } from '../../lib/prisma';
export const GET: APIRoute = async () => { const users = await prisma.user.findMany({ orderBy: { createdAt: 'desc' }, }); return new Response(JSON.stringify(users), { headers: { 'Content-Type': 'application/json' }, });};
export const POST: APIRoute = async ({ request }) => { const body = await request.json(); const user = await prisma.user.create({ data: { email: body.email, name: body.name }, }); return new Response(JSON.stringify(user), { status: 201, headers: { 'Content-Type': 'application/json' }, });};import type { APIRoute } from 'astro';import { db } from '../../lib/db';import { users } from '../../lib/schema';
export const GET: APIRoute = async () => { const allUsers = await db.select().from(users).orderBy(users.createdAt); return new Response(JSON.stringify(allUsers), { headers: { 'Content-Type': 'application/json' }, });};
export const POST: APIRoute = async ({ request }) => { const body = await request.json(); const [user] = await db.insert(users).values({ email: body.email, name: body.name, }).returning(); return new Response(JSON.stringify(user), { status: 201, headers: { 'Content-Type': 'application/json' }, });};SSR Page
Section titled “SSR Page”Fetch data server-side in the frontmatter of an .astro page:
---import { prisma } from '../lib/prisma';
const users = await prisma.user.findMany({ orderBy: { createdAt: 'desc' },});---
<html> <body> <h1>Users</h1> <ul> {users.map((user) => ( <li>{user.name} ({user.email})</li> ))} </ul> </body></html>---import { db } from '../lib/db';import { users } from '../lib/schema';
const allUsers = await db.select().from(users).orderBy(users.createdAt);---
<html> <body> <h1>Users</h1> <ul> {allUsers.map((user) => ( <li>{user.name} ({user.email})</li> ))} </ul> </body></html>Production Notes
Section titled “Production Notes”- SSR required: DB9 connections happen at request time. You must use
output: 'server'(oroutput: 'hybrid'for mixed pages). Static builds cannot query a database. - Node adapter: Use
@astrojs/nodein standalone or middleware mode. Edge adapters (Cloudflare, Vercel Edge) do not support raw TCP connections required by PostgreSQL. - Port 5433: DB9 uses port 5433, not the default PostgreSQL port 5432.
- TLS required: Always include
sslmode=requirein your connection string. - Connection pooling: Start with a small pool size (5–10). DB9 handles per-tenant connection management server-side.
Troubleshooting
Section titled “Troubleshooting”Pages return empty data or build errors
Section titled “Pages return empty data or build errors”Astro’s default output: 'static' mode pre-renders pages at build time. Database queries in .astro frontmatter or API routes require output: 'server'. Update astro.config.mjs and add the Node adapter.
ECONNREFUSED on port 5432
Section titled “ECONNREFUSED on port 5432”DB9 uses port 5433. Check that your DATABASE_URL contains :5433/ and not :5432/.
Adapter errors on deploy
Section titled “Adapter errors on deploy”DB9 requires a TCP connection (pgwire protocol). If you deploy to Cloudflare Pages, Deno Deploy, or another edge platform, the PostgreSQL driver will fail. Use @astrojs/node with a Node.js-compatible host (Docker, Railway, Fly.io, traditional VPS).
prisma db push fails
Section titled “prisma db push fails”DB9 has limited information_schema support. See the Prisma guide for workarounds.
Next Pages
Section titled “Next Pages”- Prisma — full Prisma integration guide
- Drizzle — full Drizzle integration guide
- Connect — connection strings and authentication
- Production Checklist — deployment readiness