Skip to content
Discord Get Started

Express / Hono

Express and Hono connect to DB9 through any standard PostgreSQL driver over pgwire. DB9 is PostgreSQL-compatible, so no special adapter is needed.

Terminal
db9 create --name express-app

Get the connection string:

Terminal
db9 db status express-app

Set the connection string as an environment variable:

.env
DATABASE_URL="postgresql://express-app.admin:YOUR_PASSWORD@pg.db9.io:5433/postgres?sslmode=require"
Terminal
mkdir express-db9 && cd express-db9
npm init -y
npm install express @prisma/client dotenv
npm install -D prisma typescript @types/express @types/node ts-node
npx prisma init
npx tsc --init

Set DATABASE_URL in .env (see above), then define your schema:

prisma/schema.prisma
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()) @map("created_at")
@@map("users")
}

Push the schema and generate the client:

Terminal
npx prisma db push
npx prisma generate
src/index.ts
import express from 'express';
import { PrismaClient } from '@prisma/client';
import 'dotenv/config';
const app = express();
const prisma = new PrismaClient();
app.use(express.json());
app.get('/users', async (_req, res) => {
const users = await prisma.user.findMany({
orderBy: { createdAt: 'desc' },
});
res.json(users);
});
app.post('/users', async (req, res) => {
const user = await prisma.user.create({
data: { email: req.body.email, name: req.body.name },
});
res.status(201).json(user);
});
app.get('/users/:id', async (req, res) => {
const user = await prisma.user.findUnique({
where: { id: Number(req.params.id) },
});
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
});
app.delete('/users/:id', async (req, res) => {
await prisma.user.delete({ where: { id: Number(req.params.id) } });
res.status(204).end();
});
app.listen(3000, () => console.log('Listening on http://localhost:3000'));
src/index.ts
import { Prisma } from '@prisma/client';
import { Request, Response, NextFunction } from 'express';
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
if (err instanceof Prisma.PrismaClientKnownRequestError) {
if (err.code === 'P2002') {
return res.status(409).json({ error: 'Duplicate entry' });
}
}
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
  • Port 5433: DB9 uses port 5433, not the default PostgreSQL port 5432. Double-check your DATABASE_URL.
  • TLS required: Always include sslmode=require in the connection string for DB9’s hosted service.
  • Connection pooling: Start with 5-10 connections (max option in pg.Pool, or Prisma’s connection_limit URL parameter). DB9 handles per-tenant pooling server-side.
  • Graceful shutdown: Close the database pool when the process exits to avoid leaked connections:
src/index.ts
process.on('SIGTERM', async () => {
await prisma.$disconnect();
process.exit(0);
});

DB9 uses port 5433, not 5432. Verify your DATABASE_URL includes :5433.

If you see “too many connections” errors, reduce the pool size and confirm you are not creating a new pool on every request. Reuse a single pool instance across the application.

DB9 requires TLS. Make sure your connection string includes ?sslmode=require. If you configure pg.Pool options directly, set ssl: true or ssl: { rejectUnauthorized: false } for development.

DB9 has limited information_schema support. Use prisma db push for Prisma (works in most cases) or manage tables with raw SQL for Drizzle. See the Prisma guide and Drizzle guide for details.