@terraza/db
v0.2.0
Published
Shared database client, schema, and user resolution for Terraza apps
Readme
@terraza/db
Shared database client, schema, and user resolution for Terraza apps. Centralizes the Neon serverless Pool setup, the Node.js 20 WebSocket workaround, the terraza.users Drizzle schema, and the user resolution query that every app needs.
Install
pnpm add @terraza/dbUsage
Database client
import { createDb, getDb } from "@terraza/db";
// Explicit connection string
const db = createDb(process.env.DATABASE_URL!);
// Or use the lazy singleton (reads DATABASE_URL from env)
const db = getDb();Pool for custom schemas (schema merging)
If your app needs relational queries across both terraza.users and app-specific tables, use createPool to get a WebSocket-ready Neon Pool, then pass your merged schema to drizzle():
import { createPool } from "@terraza/db";
import { terrazaUsers } from "@terraza/db/schema";
import { drizzle } from "drizzle-orm/neon-serverless";
import * as appSchema from "./schema/index.js";
const pool = createPool(process.env.DATABASE_URL!);
const db = drizzle({ client: pool, schema: { terrazaUsers, ...appSchema } });User resolution
import { resolveUser } from "@terraza/db";
const user = await resolveUser(db, "ken");
// → { id: "uuid", slug: "ken", displayName: "Ken Grafals" }Throws if the slug doesn't exist in terraza.users.
Schema
The terraza.users table definition is available as a Drizzle schema for use in queries and joins:
import { terrazaUsers, terrazaSchema } from "@terraza/db/schema";Exclude this from app-level migrations with schemaFilter in your drizzle.config.ts:
export default defineConfig({
schemaFilter: ["your_app_schema"], // omit "terraza"
});Exports
@terraza/db
| Export | Purpose |
|--------|---------|
| createDb(url) | Create a Drizzle client from a Neon connection string |
| createPool(url) | Create a Neon Pool with WebSocket workaround (for schema merging) |
| getDb() | Lazy singleton that reads DATABASE_URL from env |
| resetDb() | Clear the singleton (for tests) |
| resolveUser(db, slug) | Query terraza.users by slug, throw if not found |
| terrazaSchema | Drizzle pgSchema("terraza") |
| terrazaUsers | Drizzle table definition for terraza.users |
| DbClient | Type alias for the Drizzle client |
| Pool | Type alias for the Neon serverless Pool |
| ResolvedUser | Type: { id, slug, displayName } |
| User | Inferred select type for terraza.users |
| NewUser | Inferred insert type for terraza.users |
@terraza/db/schema
Re-exports terrazaSchema, terrazaUsers, User, and NewUser for use in Drizzle configs and queries without pulling in the full package.
WebSocket workaround
Node.js 20 lacks a global WebSocket. This package detects that and configures @neondatabase/serverless to use the ws package automatically. When the VPS upgrades to Node 22+, this becomes a no-op — no changes needed in consuming apps.
Environment variables
| Variable | Purpose |
|----------|---------|
| DATABASE_URL | Neon connection string (used by getDb()) |
Development
npm run build # TypeScript compilation to dist/
npm test # Run vitest suite (9 tests)