Skip to content
Node.js8 min read

PostgreSQL in Node.js: node-postgres vs Prisma vs Drizzle

Raw SQL with pg, the batteries-included Prisma, or the SQL-shaped Drizzle? A working comparison from teams that run all three in production.

Postgres is the least controversial choice in backend engineering; how to talk to it from Node is anything but. We maintain client systems on node-postgres, Prisma and Drizzle, which gives us a reasonably fair vantage point. The short version: all three are good, and the decision is really about how much SQL your team wants to see.

node-postgres: the honest baseline

The pg package is the foundation nearly everything else builds on. You write SQL, you get rows. There is no schema layer, no migration engine and no types beyond what you assert — and for teams fluent in SQL, that directness is a feature. Window functions, CTEs, partial indexes and every Postgres extension are available on day one, because there is no abstraction to wait on.

js
import pg from 'pg';

const pool = new pg.Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
});

const { rows } = await pool.query(
  'select id, email from users where created_at > $1',
  [since]
);

Two non-negotiables if you go this route: always use parameterised queries as above, and always use a Pool rather than ad hoc clients — connection setup is expensive and Postgres has a hard connection ceiling. Pair pg with a plain migration tool such as node-pg-migrate and you have a stack with no magic to debug.

Prisma: the productivity play

Prisma inverts the model: you describe your schema in its own language, and it generates a fully typed client plus migrations. Autocomplete across relations is genuinely excellent, and for CRUD-heavy products it is the fastest way we know to ship. The costs are a build step, an opinionated query layer that can generate more SQL than you would write by hand for complex reads, and a certain distance from the database when things get subtle. Recent Prisma versions have removed the old Rust engine binary, which improved cold starts and deployment friction considerably.

Our rule with Prisma is to let it own the crud and drop to $queryRaw with typed results for reporting queries — using each tool where it is strong rather than forcing one to do everything.

Drizzle: SQL that type-checks

Drizzle sits deliberately between the two. Schemas are TypeScript, queries look like SQL with the words rearranged, and everything infers end-to-end types with no code generation step. If you know SQL, you already mostly know Drizzle, and what it compiles to is rarely a surprise.

ts
const recent = await db
  .select({ id: users.id, email: users.email })
  .from(users)
  .where(gt(users.createdAt, since))
  .orderBy(desc(users.createdAt))
  .limit(20);

Migrations deserve a word, because each tool has its own culture. Prisma Migrate diffs the schema file and writes the SQL for you; Drizzle Kit generates SQL from your TypeScript schema and expects you to read it; with pg you write it yourself. Whichever engine runs them, the rules are the same: migrations run in CI before deploy, they are forward-only in shared environments, and anything touching a large table gets rehearsed against a production-sized copy first, because an innocent-looking ALTER can take a lock you will remember.

Choosing between them

  • Team fluent in SQL, complex analytical queries: node-postgres, or Drizzle if you want types on top.
  • Product team optimising for shipping CRUD features quickly: Prisma.
  • TypeScript-first team that wants zero codegen and close-to-the-metal SQL: Drizzle.
  • Serverless deployments: check driver support carefully — connection pooling behind a proxy such as PgBouncer matters more than the ORM choice.

Whatever you choose, keep the data layer behind your own repository functions. Every painful migration between these tools we have performed was painful precisely because queries were scattered through handlers rather than gathered in one place.

Wrestling with a data layer decision or a slow Postgres setup? That is bread-and-butter work for STRCLI.

Start your project

Have an idea? Let's ship it together.

Tell us what you're building — we'll reply within one business day with an honest take and a clear next step.