node-postgres: Non-Blocking PostgreSQL Client for Node.js
PostgreSQL client for node.js.
At a glance
- What is it?
- node-postgres (published as the pg package) is a non-blocking PostgreSQL client for Node.js, Bun, Deno, and Cloudflare Workers, offering pure JavaScript by default and optional native libpq bindings through pg-native. It is a low-level client, not an ORM: you write SQL and get back rows.
- Who is it for?
- node-postgres is the right choice for Node.js applications that need direct PostgreSQL access without the abstraction layer of an ORM. Teams that want automatic migration generation, a model definition layer, or a query builder should evaluate Prisma or Drizzle instead.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What node-postgres Is and What It Does Not Do
node-postgres is a PostgreSQL protocol implementation for Node.js. The pg package sends SQL queries to a PostgreSQL server, parses the wire protocol responses, and returns JavaScript objects. That is the complete scope. There is no schema definition layer, no migration generator, no model class system, and no query builder. You write SQL strings; node-postgres executes them and hands back the result rows.
The README is direct about this positioning: node-postgres is by design light on abstractions. The project author maintains a wiki of community-built extras for teams that need higher-level functionality on top of pg, but none of those extras are part of the published pg package itself.
This design choice has consequences in both directions. On the positive side, there is no ORM abstraction between your queries and PostgreSQL. You can use any PostgreSQL feature, any SQL syntax the server supports, and any stored procedure without worrying about whether the query builder can express it. On the negative side, there is no automatic type mapping beyond the built-in JavaScript type coercions, no schema migration tooling, and no query builder to compose complex queries programmatically.
The README lists the runtimes that node-postgres supports beyond Node.js: Bun, Deno, and Cloudflare Workers. The pure JavaScript client is what enables this portability; the native libpq bindings (in pg-native) work only in environments that can build native modules, which excludes edge runtimes.
The Monorepo Structure and What Each Package Does
The repository is a Yarn monorepo containing seven packages, each published separately to npm.
pg is the core package, the one most applications install. It exports the Client and Pool classes. pg-pool implements connection pooling and is listed as a separate package, but the main pg package includes pool functionality by re-exporting pg-pool. Applications can use pg directly and get pooling without installing pg-pool separately, or use pg-pool as a standalone pool if they want to configure it independently.
pg-native provides the optional native libpq bindings. The README notes that the pure JavaScript client and pg-native share the same API, meaning you can swap between them without changing application code. pg-native requires libpq-dev to be installed on the system when building, which is documented in the contributing setup steps. The README suggests installing pg-native only when you have a measured performance need, not as a default.
pg-cursor enables cursor-based result streaming, allowing large result sets to be consumed row by row without loading the entire result into memory. This is distinct from pg-query-stream, which wraps a cursor in a Node.js Readable stream interface for pipe-based consumption.
pg-connection-string parses PostgreSQL connection strings into configuration objects. pg-protocol contains the low-level wire protocol implementation that both the JavaScript client and pg-native build on. These lower-level packages are also available separately so other tools in the PostgreSQL ecosystem can depend on them without taking the full pg package.
The workspace is managed with Yarn (lerna 3.x for cross-package test running) and built with TypeScript 6 for type declarations.
Installing pg and Making a First Query
Install the core package with npm:
npm install pgThe pg package exports Client for single-connection use and Pool for connection pooling. The README does not show inline code examples for typical usage, but the documented features include parameterized queries, named statements with query plan caching, async notifications via LISTEN and NOTIFY, and bulk data transfer via COPY TO and COPY FROM.
For local development and testing, the README lists the environment variables that node-postgres reads for connection configuration. These follow PostgreSQL's own standard PG* variable convention: PGUSER, PGPASSWORD, PGHOST, PGPORT, and PGDATABASE. Setting these environment variables means you do not have to pass connection parameters in code, keeping credentials out of source files.
The PGTESTNOSSL=1 environment variable appears in the contributing documentation as a way to skip SSL-related tests when setting up a local development environment without SSL configured. In production, the README implies SSL-enabled PostgreSQL is the standard expectation, not an optional extra.
Contributing to node-postgres requires a PostgreSQL instance with SSL enabled and an empty test database. The contributing steps state to run yarn lerna bootstrap after yarn to link the monorepo packages together, then yarn test to run all test suites across all packages. The benchmark/ directory contains a compare.js script runnable with yarn benchmark.
Connection Pooling and the pg-pool Package
Most production applications use a connection pool rather than creating a new database connection for each query. Opening a new TCP connection and authenticating with PostgreSQL for every request adds latency and consumes server resources. A pool maintains a set of established connections and hands them out to callers as needed.
node-postgres implements pooling through pg-pool. The Pool class manages connection lifecycle: creating new connections up to the configured maximum, recycling idle connections, and queuing requests when all connections are busy. The README describes the Pool as part of the features list, alongside parameterized queries and named statements.
Named statements with query plan caching are a specific optimization in node-postgres. When you send the same parameterized query multiple times, PostgreSQL parses and plans it once and caches the plan for subsequent calls. node-postgres exposes this through prepared statement naming. This is a PostgreSQL-specific optimization that ORM layers often do not expose directly, since they generate queries dynamically. With node-postgres, you control when a statement is named and when it should be re-planned.
LISTEN and NOTIFY are PostgreSQL's built-in asynchronous notification mechanism. node-postgres supports both sides: sending NOTIFY to a channel and subscribing to a channel with LISTEN to receive notifications as JavaScript events. This enables patterns like real-time database change notifications without polling, useful for applications that need to react to database-level events.
COPY TO and COPY FROM enable bulk data transfer between PostgreSQL and Node.js streams. For loading large datasets, COPY FROM is significantly faster than executing many individual INSERT statements, since it bypasses row-level parsing overhead on the PostgreSQL side.
node-postgres vs Prisma: When to Choose Each
Prisma is the most commonly mentioned comparison when evaluating node-postgres. The two differ in abstraction level, not just syntax.
Prisma is a data access platform that includes a schema definition language (schema.prisma), a migration generator, a type-safe query builder (Prisma Client), and an optional GUI (Prisma Studio). Prisma generates TypeScript types from your schema, so query results are typed at compile time. The trade-off is that Prisma's query API covers the SQL operations Prisma knows how to generate. Complex queries, database-specific functions, or unconventional SQL patterns may require dropping down to Prisma's raw query escape hatch.
node-postgres has no schema language, no migration generator, and no query builder. You get typed results only if you add TypeScript type annotations yourself. Every query is raw SQL, which means any SQL the server supports works without workarounds. Teams comfortable writing SQL and willing to manage their own migration tooling (for example, with a dedicated migration library) will find node-postgres gives them full control.
For new projects where developer productivity matters more than SQL control, Prisma's generated types and migration workflow reduce certain categories of errors. For projects where the team already knows PostgreSQL well, where performance tuning requires specific query shapes, or where the schema is too complex for a code-first ORM, node-postgres is the appropriate layer.
The README also mentions Sequelize and Drizzle in the context of related tools. Sequelize is an older Node.js ORM with broad database support but less TypeScript-first design than Prisma. Drizzle is a newer query builder with a SQL-like API that generates TypeScript types, positioned between node-postgres (raw SQL) and Prisma (full ORM) in terms of abstraction level.
Known Limitations and Failure Modes
node-postgres does not implement connection retry logic. If a connection is lost to the database while a query is in flight, the query fails with an error. Application code is responsible for detecting connection failures and retrying. This is different from some ORMs and higher-level connection managers that implement automatic reconnect.
The native libpq bindings in pg-native provide a different code path than the pure JavaScript client. The README states they share the same API, but the native module requires compilation during npm install and depends on the libpq system library version. This adds a build-time dependency that can fail in Docker images or CI environments where libpq-dev is not installed. Using the native bindings without a measured performance need introduces a build complexity that often is not worthwhile.
The FAQ linked in the README covers common errors, but the FAQ lives on a GitHub wiki page rather than in the repository itself. This means it is not easily versioned alongside the code, and answers may refer to older API behavior if the wiki has not been updated to match recent releases.
The repository has no GitHub releases. The last push to master was on 2026-09-24. Versioning for individual packages in the monorepo appears in each package's own package.json. The root package.json does not itself publish to npm; it is the private workspace root.
Multiple connection pool instances sharing the same PostgreSQL server can exhaust the server's max_connections setting. This is not a bug in node-postgres but a configuration boundary that application teams need to account for, particularly in serverless deployments where each function instance may create its own pool.
Maintenance, Sponsorship, and MIT License
node-postgres is maintained by Brian Carlson and has been in development since 2010, as stated in the copyright notice in the LICENSE file (Copyright 2010-2020 Brian Carlson). The last push to master was on 2026-09-24, indicating ongoing maintenance activity.
The README includes a sponsorship section. The project acknowledges financial support from the community through GitHub Sponsors. The README names medplum as a featured sponsor. Carlson can be contacted on Bluesky at brianc.bsky.social; the README notes his Twitter/X account is no longer active.
The MIT license is straightforward for commercial use: you can use, modify, and distribute node-postgres in commercial applications without restriction. There is no copyleft requirement, no contributor license agreement for users, and no dual-licensing arrangement.
The SPONSORS.md file in the repository lists financial contributors. This transparency about project funding is relevant for organizations evaluating whether the project has adequate maintenance resources for a dependency they plan to build on.
All support requests go through GitHub issues. The README asks issue reporters to provide the Node.js version, PostgreSQL version, and the smallest reproducible code snippet. The issue tracker doubles as the FAQ supplementary resource: questions with documented answers appear in the GitHub wiki FAQ, and edge cases that are not documented there are handled through new issues.
Editorial conclusion
node-postgres is the right choice for Node.js applications that need direct PostgreSQL access without the abstraction layer of an ORM. Teams that want automatic migration generation, a model definition layer, or a query builder should evaluate Prisma or Drizzle instead. Before adopting pg, verify that your PostgreSQL server version is compatible and that SSL is configured if required, since the README notes tests can be skipped per PGTESTNOSSL=1 but production deployments typically need SSL. The last push to master was on 2026-09-24. The project is MIT-licensed and has been in active development since 2010.
Frequently asked questions
What is node-postgres?
node-postgres (pg) is a non-blocking PostgreSQL client for Node.js, Bun, Deno, and Cloudflare Workers that sends SQL queries to a PostgreSQL server and returns result rows as JavaScript objects. It is not an ORM: it has no schema layer, no migration generator, and no query builder.
Is node-postgres an ORM?
No. node-postgres is a low-level database client that executes SQL strings and returns result rows. The README explicitly states the project is light on abstractions. For an ORM or type-safe query builder on top of PostgreSQL, Prisma or Drizzle are common choices.
How do I install node-postgres?
Run npm install pg in your project directory. The pg package includes Client for single connections and Pool for connection pooling. The pg-native package is an optional separate install if you want native libpq bindings instead of the pure JavaScript implementation.
What is the difference between the node-postgres client and pool?
Client manages a single database connection and requires manual connect and release calls. Pool manages multiple connections, reusing them across requests to reduce connection overhead. Most production applications use Pool; Client is useful for long-lived tasks like LISTEN or COPY operations that should not share a pooled connection.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/brianc-node-postgres)