Databases Basics
8 examples to get you started with databases for Node.js backends - 6 basic and 2 intermediate.
Search across all documentation pages
8 examples to get you started with databases for Node.js backends - 6 basic and 2 intermediate.
npm install pg
npm install -D typescript@5.6 tsx @types/pgFor pool tuning and ORM trade-offs, see node-postgres (pg) and Prisma.
| Need | SQL (Postgres) | Document (MongoDB) |
|---|---|---|
| Joins and constraints | Strong fit | Weaker; embed or $lookup |
| Schema evolution | Migrations | Flexible fields |
| Reporting / BI | Mature tooling | Aggregation pipelines |
| ACID transactions | Native multi-row | Multi-doc since 4.0 |
pg or Drizzle/PrismaRelated: MongoDB Driver - document patterns
// src/config.ts
import { z } from "zod";
const env = z.object({
DATABASE_URL: z.string().url(),
}).parse(process.env);
export const databaseUrl = env.DATABASE_URL;DATABASE_URL format: postgres://user:pass@host:5432/dbnamepg Poolimport pg from "pg";
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
max: 10,
idleTimeoutMillis: 30_000,
});
export async function getUser(id: string) {
const { rows } = await pool.query(
"SELECT id, email FROM users WHERE id = $1",
[id]
);
return rows[0] ?? null;
}$1, $2 placeholders - never string concatmax should match expected concurrent queries, not CPU count aloneRelated: Connection Pool Tuning - sizing math
import pg from "pg";
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
process.on("SIGTERM", async () => {
await pool.end();
process.exit(0);
});pool.end() waits for checked-out clients to returnclose() in graceful shutdown handlersimport type pg from "pg";
export async function withTransaction<T>(
pool: pg.Pool,
fn: (client: pg.PoolClient) => Promise<T>
): Promise<T> {
const client = await pool.connect();
try {
await client.query("BEGIN");
const result = await fn(client);
await client.query("COMMIT");
return result;
} catch (err) {
await client.query("ROLLBACK");
throw err;
} finally {
client.release();
}
}BEGIN/COMMITimport type { Pool } from "pg";
export async function checkDatabase(pool: Pool): Promise<boolean> {
try {
await pool.query("SELECT 1");
return true;
} catch {
return false;
}
}totalCount and idleCount on repeated failures// src/domain/user.ts
export type User = { id: string; email: string };
export interface UserRepository {
findById(id: string): Promise<User | null>;
create(email: string): Promise<User>;
}
// src/infrastructure/pg-user-repo.ts
import type { Pool } from "pg";
import type { User, UserRepository } from "../domain/user";
export function createPgUserRepo(pool: Pool): UserRepository {
return {
async findById(id) {
const { rows } = await pool.query(
"SELECT id, email FROM users WHERE id = $1",
[id]
);
return rows[0] ?? null;
},
async create(email) {
const { rows } = await pool.query(
"INSERT INTO users (email) VALUES ($1) RETURNING id, email",
[email]
);
return rows[0];
},
};
}Related: Use Cases & Services - orchestration layer
| Layer | pg raw | Drizzle | Prisma |
|---|---|---|---|
| Control | Full SQL | SQL-first typed | Schema-first |
| Migrations | flyway, dbmate, drizzle-kit | drizzle-kit | prisma migrate |
| N+1 risk | You control joins | You control joins | Watch include |
| Learning curve | Low | Medium | Medium |
pg or Drizzle with raw queriesBoth work. Postgres leads for JSONB, extensions, and managed cloud options. Pick what your team operates well.
No. pg plus SQL files is valid. ORMs help migrations and TypeScript inference at the cost of abstraction leaks.
One per database URL. Multiple pools to the same DB waste connections.
Use a pooler (PgBouncer, Neon, Supavisor). See Connection Pool Tuning.
In CI/CD before deploy, never manual prod DDL. See Databases Best Practices.
Yes via @nestjs/typeorm, Prisma module, or custom provider wrapping Pool.
In-memory repository for unit tests; Testcontainers Postgres for integration tests.
Creating a new connection per request instead of pooling.
pg) - pool and transactionsmax and PgBouncerStack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 16, 2026