| title | Drizzle |
|---|---|
| icon | Droplets |
| tag | TypeScript |
| description | Connect Drizzle ORM to your PostgreSQL database through PgBeam for connection pooling, caching, and global routing. |
Connect your Drizzle ORM application to PgBeam by updating the connection string. No changes to your schema definitions, table declarations, or queries are required.
### Update your environment```bash title=".env"
DATABASE_URL=postgresql://user:pass@abc.aws.pgbeam.app:5432/mydb
```
<Tabs items={["Simple", "With pool config"]}>
<Tab value="Simple">
```ts title="db.ts"
import { drizzle } from "drizzle-orm/node-postgres";
const db = drizzle(process.env.DATABASE_URL!);
```
</Tab>
<Tab value="With pool config">
```ts title="db.ts"
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 5, // PgBeam handles upstream pooling — keep this low
});
const db = drizzle(pool);
```
</Tab>
</Tabs>
```ts
const users = await db.select().from(usersTable);
```
If this returns results, Drizzle is connected through PgBeam.
PgBeam handles upstream connection pooling, so the pg pool on your application
side should be small. A pool size of 3-5 per application instance is typically
sufficient.
| Deployment type | Recommended max pool size |
|---|---|
| Single server | 5-10 |
| Multiple replicas/pods | 3-5 per instance |
| Serverless (Lambda) | 1-2 |
DATABASE_URL="postgresql://user:pass@db.example.com:5432/mydb" npx drizzle-kit migrateThe same applies to drizzle-kit push for development:
DATABASE_URL="postgresql://user:pass@db.example.com:5432/mydb" npx drizzle-kit pushFor standard Drizzle query builder queries (db.select(), db.query, etc.),
PgBeam automatically tracks the generated SQL shapes. Enable caching for these
through Cache Rules in the dashboard — no code changes needed.
Use Drizzle's sql template for fine-grained cache control:
import { sql } from "drizzle-orm";
// Cache for 10 minutes
const categories = await db.execute(
sql`/* @pgbeam:cache maxAge=600 */ SELECT * FROM categories`,
);
// Disable caching for a specific query
const balance = await db.execute(
sql`/* @pgbeam:cache noCache */ SELECT balance FROM accounts WHERE id = ${accountId}`,
);Route read queries to replicas using the /* @pgbeam:replica */ annotation:
import { sql } from "drizzle-orm";
// Route to a read replica
const products = await db.execute(
sql`/* @pgbeam:replica */ SELECT * FROM products WHERE active = true`,
);
// Combine replica routing with caching
const stats = await db.execute(
sql`/* @pgbeam:replica */ /* @pgbeam:cache maxAge=300 */ SELECT count(*) FROM orders`,
);Standard query builder calls always go to the primary database. To use replica routing, use raw SQL with the annotation.
See Read Replicas for details on replica setup.
Enable PgBeam debug output to verify caching and routing:
import { sql } from "drizzle-orm";
await db.execute(sql`SET pgbeam.debug = on`);
const result = await db.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
// Check server logs for: NOTICE: pgbeam: cache=hit age=12s ttl=60s swr=30s| Issue | Cause | Fix |
|---|---|---|
| "Too many connections" errors | pg pool too large |
Set max: 5 in Pool config |
| Migrations fail through PgBeam | Session features not available | Run migrations against origin directly |
| Stale data after writes | Cache returning old results | Use noCache annotation or adjust TTL |
- Connection Pooling — Pool modes and sizing guidance
- Caching — TTL, SWR, cache rules, and SQL annotations
- Read Replicas — Replica setup and routing