mrkeyoor.com_
Sat 19 Sept 08:53 UTC
npmDataupdated 19 Sept 2026

pg review

pg 8.23.0, the main node-postgres package, is a server-side PostgreSQL driver for Node. It opens clients and pools, sends parameterized SQL, exposes transactions and prepared statements, decodes result rows, and supports LISTEN/NOTIFY. Schema definitions and migrations remain your responsibility or belong to another tool. Version 8.23 adds opt-in query pipelining: independent statements can be sent on one client before earlier responses return, while each query keeps its own result or error. The connection still processes those statements in order, so pipelining is different from parallel work on several pooled connections.

48.4Mdownloads / wk
Verdict

pg 8.23.0 installed in 1.3 seconds and used 1 MB in our sandbox, so the runtime cost is small for Node teams that want raw PostgreSQL control. Skip it when you need bundled TypeScript types, browser execution, generated schemas, or an abstraction that owns migrations and identifier composition.

We installed it

Lab card: what happened when we installed pgScreenshot of pg documentation
Install✓ · 1.3s14 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package with exports map
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does pg install cleanly?

Yes. In a fresh container with an empty cache, npm install pg finished in 1 seconds, leaving 14 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

Can pg run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does pg work with both ESM and CommonJS?

Yes. Both import 'pg' and require('pg') worked in Node 22 in our run. The package is published as CommonJS with an exports map.

Does pg include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

pg or postgres: which should you use?

Pick postgres when postgres 3.x fits when tagged-template SQL and built-in TypeScript declarations are preferred over pg's query config API. pg 8.23.0 installed in 1.3 seconds and used 1 MB in our sandbox, so the runtime cost is small for Node teams that want raw PostgreSQL control.

When should you not use pg?

A TypeScript project requires declarations from the runtime package itself. Our package check found no TypeScript types in pg 8.23.0.

API stability5/5Client, Pool, pool.query, client.query, positional parameters, result.rows, transactions, and environment-variable configuration have remained the center of node-postgres through the 8.x line. Version 8.23 adds pipeline mode behind an explicit client option instead of changing ordinary query ordering. Advanced areas such as SSL parsing and global type parsers still need upgrade tests because a small configuration change can affect every connection or decoded row.
Docs5/5node-postgres.com documents connecting, environment variables, pooling, queries, parameters, prepared statements, row modes, data types, transactions, SSL, cursors, notifications, async APIs, and pool sizing. Examples make the same-client transaction rule and pool error handling explicit. The docs assume readers already understand PostgreSQL operations, so migration strategy, SQL design, certificate sourcing, and provider connection limits remain outside the package guide.
Maintenance4/5npm published 8.23.0 on August 8, 2026, and GitHub records a push on August 18, 2026. The repository is unarchived with 13,198 stars and 518 open issues and pull requests across the monorepo. New pipeline support shows feature work continues, although the large open queue and multiple sibling packages make a raw GitHub count less useful than release notes and tests for the exact package.
Ecosystem5/5npm counted 48,602,400 downloads in the latest completed week, and GitHub reports 13,198 stars. Many Node ORMs, migration tools, job systems, and frameworks use pg or accept its Pool and Client objects. Sibling packages add cursors, query streams, COPY helpers, and native bindings. The package is a common interoperability layer, but its missing bundled TypeScript declarations require another type source in typed applications.

Use it if

  • pg 8.23.0 fits a Node service that wants direct PostgreSQL SQL and a small built-in connection pool.
  • Queries need positional parameters, prepared statement names, transaction control, or LISTEN/NOTIFY without adopting an ORM.
  • The team is prepared to own migration tooling, pool limits, transaction boundaries, identifier safety, and PostgreSQL-specific SQL.
  • Independent statements on one connection may benefit from 8.23's explicit pipeline mode and do not depend on earlier results.
Skip it if

Setup reality

We installed pg 8.23.0 in a fresh Node 22 Bookworm sandbox. npm took 1.3 seconds, left 14 packages, and used 1 MB. npm audit found 0 known vulnerabilities. The package has 5 direct dependencies, 1 peer dependency, and 164 KB unpacked. It declares Node >=16.0.0 and uses CommonJS with an exports map. Both require() and ESM import worked under Node 22.23.2. No TypeScript declarations were found.

Our esbuild browser bundle failed, which matches a database driver meant for trusted Node processes. Configure PGHOST, PGPORT, PGUSER, PGPASSWORD, and PGDATABASE or pass a connectionString. SSL is not inferred safely for every provider. Use the provider's certificate requirements, and be careful that sslmode parameters in a connection string can replace a separately supplied ssl object. Do not ship credentials to frontend code.

Pool.query is correct for one statement. A transaction must check out one client, issue BEGIN, all statements, and COMMIT on that same client, then release it in finally. Pool size should fit the database connection budget across every process and replica. Add a pool error handler because an idle client can still receive a network error. End the pool in scripts and graceful shutdown paths.

Parameters bind values only. Never interpolate untrusted identifiers into SQL. PostgreSQL int8 and numeric values return as strings by default to avoid silent precision loss; choose a column-specific conversion or a global type parser only when the value range is known. Version 8.23 pipeline mode is opt-in with pipeline: true. It reduces round trips for independent ordered queries, but a query cannot use a result that has not arrived.

Patterns

Parameterize a pooled query query-pool

import pg from 'pg';
const { Pool } = pg;
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

const result = await pool.query('SELECT id, email FROM users WHERE id = $1', [userId]);

$1 binds a value and blocks value-based SQL injection. It cannot stand for a table or column identifier.

Keep a transaction on one client run-transaction

const client = await pool.connect();
try {
  await client.query('BEGIN');
  await client.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, from]);
  await client.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, to]);
  await client.query('COMMIT');
} catch (error) {
  await client.query('ROLLBACK');
  throw error;
} finally {
  client.release();
}

Do not use pool.query inside this block. Each call could select a different database session.

Catch errors from idle pooled clients handle-pool-errors

pool.on('error', (error) => {
  console.error('unexpected PostgreSQL client error', error);
});

An idle checked-in connection can fail after a network break. Without this listener, the pool emits an unhandled error event.

Load the provider CA certificate configure-tls

import fs from 'node:fs';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { ca: fs.readFileSync(process.env.PG_CA_FILE, 'utf8') },
});

Use the certificate and verification mode required by the provider. Connection-string SSL parameters can replace this ssl object.

Convert int8 only with a safe range parse-bigint

import pg from 'pg';
pg.types.setTypeParser(20, (value) => {
  const parsed = BigInt(value);
  if (parsed > BigInt(Number.MAX_SAFE_INTEGER)) return parsed;
  return Number(parsed);
});

OID 20 is int8. This global parser changes every matching result, so returning mixed number and bigint types needs caller agreement.

Name a frequently reused statement prepare-query

await client.query({
  name: 'user-by-id',
  text: 'SELECT id, email FROM users WHERE id = $1',
  values: [userId],
});

Prepared statement names are scoped to a connection. Reuse one name only with the same SQL text.

Receive PostgreSQL notifications listen-notify

const client = await pool.connect();
client.on('notification', (message) => {
  console.log(message.channel, message.payload);
});
await client.query('LISTEN job_events');

Keep this client checked out while listening. Reconnect and LISTEN again after connection loss.

Close a one-off process cleanly close-pool

try {
  await runJob(pool);
} finally {
  await pool.end();
}

pool.end() rejects new work and closes idle clients after checked-out clients return. Servers usually call it during graceful shutdown.

Alternatives

PackageRegistryPick it when
postgresnpmpostgres 3.x fits when tagged-template SQL and built-in TypeScript declarations are preferred over pg's query config API.
mysql2npmUse mysql2 when the database is MySQL or MariaDB; it is not a PostgreSQL substitute on the same server.
better-sqlite3npmUse better-sqlite3 for an embedded SQLite database where a network pool and PostgreSQL server are unnecessary.

More data guides

numpy · fsspec · pandas · pyarrow · sqlalchemy · s3fs · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.