Skip to content

chore(deps): bump postgres from 3.4.9 to 4.0.0 - #956

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/postgres-4.0.0
Open

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/postgres-4.0.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Nov 2, 2026

Copy link
Copy Markdown
Contributor

Bumps postgres from 3.4.9 to 4.0.0.

Release notes

Sourced from postgres's releases.

v4.0.0

v4 rewrites everything below the public API: the pool, the connection, the protocol, startup and the socket layer. Queries, helpers, transactions, cursors, COPY, listen, subscribe, large objects and the options work as in 3.4.9, apart from the changes below.

Security

  • A NUL character in a connection parameter can no longer add parameters (also in v3). A database, user or connection value such as 'db\0user\0postgres' was sent as further startup parameters, so an app that put untrusted input there, as with a database per tenant, could be made to log in as another user where that user needs no password, or with replication or options set. A NUL in any protocol string, also in query text and identifiers, now rejects with NUL_CHARACTER.
  • A column named __proto__ is an own property (also in v3). It became the prototype of the row, so a JSON value in it, for instance from a column alias built from user input, made the row inherit its properties (row.isAdmin), in query results and in sql.subscribe rows alike.

Upgrading from v3

The README has an upgrade guide, with a query that shows whether the change in parameter types concerns you.

  • The server decides the type of every parameter (infer: false by default) (#392). v3 typed a Date as timestamptz, a boolean, a Buffer, a bigint and arrays of these from JavaScript; v4 sends them without a type and writes each value for the type the server asks for, as libpq does. timestamptz columns, values written to a column of their own type, strings, numbers and anything cast work as before. Outside UTC, a Date written to or compared with a timestamp or date column is taken as UTC instead of the session's local time, and a timestamp is read as UTC, so it comes back as the instant that was written whatever the time zone. A Date where the query doesn't decide its type, such as in date_trunc('day', ${ date }), needs a cast (${ date }::timestamptz). infer: true keeps v3's behaviour.
  • Runtimes. Node.js 20 or later, Bun, and Cloudflare Workers; Deno through its Node.js compatibility. The CommonJS and Deno builds are gone: Postgres.js is an ES module, which require can load on Node.js 20.19 and 22.12 and later (require('postgres').default).
  • sql.array() is removed. Pass the array as it is, with a cast where the query doesn't decide its type: ${ ids }::int[]. Calling sql.array() throws ARRAY_REMOVED.
  • A transaction the server rolled back rejects. When the server answers COMMIT with ROLLBACK, sql.begin rejects with TRANSACTION_ROLLED_BACK; v3 took it as a commit.
  • A released connection stays released. A query on a reserved sql after release(), or on a transaction's sql after it has committed or rolled back, rejects; v3 ran it on whatever connection it then had. Releasing a reserved connection while its own BEGIN is still open closes it instead of returning an open transaction to the pool.
  • An unsafe begin outside sql.begin, a reserved connection or max: 1 rejects with UNSAFE_TRANSACTION and is rolled back. A query that looks like it may open a transaction runs alone on its connection, so nothing else lands in it, and any query that leaves its connection in a transaction is rolled back and rejected. v3 rejected BEGIN but left the transaction open. A script that opens and closes its own transaction in one query, such as a migration file with BEGIN and COMMIT, runs; v3 ran it and still rejected it.
  • A query that cannot be built or serialized inside a transaction aborts the transaction, in sql.begin (#1236, #1238) or one opened by hand on a reserved connection, just as a server error would: the queries after it fail with 25P02 and a later COMMIT answers ROLLBACK. v3 skipped the query and let the rest commit.
  • Domains that exist when the pool starts are read and written as their base type, so a domain over int[] comes back as an array of numbers; v3 returned the text.
  • A connection refused for too many connections (53300) is retried with backoff until connect_timeout has passed, and the waiting queries reject with that error only then. Such a refusal is often momentary: connections opened at the same time against a connection limit can all be refused while the server counts them. v3 rejected the queries of the refused connection at once.
  • No host matching target_session_attrs rejects with CONNECTION_DESTROYED instead of retrying forever.
  • An unknown authentication type rejects with AUTH_TYPE_NOT_IMPLEMENTED instead of waiting for the connect timeout.
  • A replication error with no onerror is logged. When the sql.subscribe stream fails and none of its subscriptions has an onerror, the error goes to console.error before the stream reconnects; v3 dropped it. Pass onerror to handle or silence it.
  • infinity timestamps are Infinity and -Infinity, both ways, instead of an invalid Date.
  • TypeScript: the types are an ES module with a default export and named types (import postgres, { type Sql } from 'postgres'). A reserved connection is no longer typed as having begin and end, which it never had.

New

  • Scheduling across connections: when every connection is busy, a query is pipelined on the connection where it should be done soonest, from how long each statement took before and how long what is in flight has run, and slow queries are kept together once the rest of the pool is needed for quick ones. In simulations of mixed workloads, the p99 of quick queries fell 2 to 100 times; on PostgreSQL, a 1 ms lookup no longer waits behind a report on a busy pool (p99.9 from 792 ms to 5 ms). scheduler: false pipelines on the busy connection with the fewest queries in flight instead; v3 went round-robin over the busy connections. With max: 1 it is off, as there is only one connection.
  • queue_timeout: seconds a query, transaction or reserve may wait for a connection before it rejects with QUEUE_TIMEOUT, unsent (#1036, #824).
  • .signal(abortSignal) on a query: aborting rejects it if it is still waiting, or cancels it if it is running.
  • Canceling a cursor between batches stops it. .cancel() or an aborted .signal() while the cursor's callback runs, or while an async iterator over it is between batches, fetches no more rows, closes the portal and rejects with 57014. v3 sent a cancel request that the idle server ignored, so the cursor ran on to the end (or, arriving late, could cancel the next query).
  • sql` and `.join(items) joins fragments and values with a fragment as separator, leaving out falsy items and adding spaces where missing (#807, #813).
  • Nested sql.begin inside a transaction runs in a savepoint (#985).
  • sql.rollback() rolls back a transaction, or the savepoint it is called in, without throwing; sql.begin resolves with the callback's result (#500).
  • Pipelining anywhere in a transaction is documented and tested: queries in a Promise.all between awaited ones are sent together and run in the order they were made (#951).
  • Custom types by name: to and from can be type names, looked up when the pool starts, with array types, for extension types such as pgvector (#1115, #719).
  • using and await using: sql ends the pool and a reserved connection is released when it goes out of scope (#886, #1094).
  • unref_sockets: true lets the process exit while connections are idle, like allowExitOnIdle in node-postgres (#869, #918).
  • min: connections kept open once the pool is used; idle_timeout closes only those above it (#672).
  • user as a function, called each time a connection opens, like password, for credentials that rotate (#881).
  • Password file: with no password given, PGPASSFILE or ~/.pgpass is read as libpq reads it (#964).
  • Named arguments: an object in the parentheses of a function call becomes name => value arguments, make_interval(${ sql({ days: 1 }) }) (#1040).
  • Errors are documented with their fields and how to tell them apart (#1140).
  • COPY row count: a copy ... from stdin writable has count and command once it has finished, with the number of rows the server copied (#465).
  • Persistent replication slots: slot: 'name' keeps the slot of sql.subscribe across restarts and streams from where it was last confirmed. A transaction is confirmed only once its handlers have finished, a handler that fails gets its transaction delivered again, and handlers may be async: they run one after the other in commit order while the stream waits.
  • More from sql.subscribe: truncate events, and the lsn, time and xid of the transaction on every change. Reconnecting retries with backoff.
  • Channel binding: over TLS, SCRAM authenticates with SCRAM-SHA-256-PLUS (tls-server-end-point) when the server offers it, binding the login to the server certificate. channel_binding is 'prefer' by default, 'require' or 'disable' as in libpq, also from the url or PGCHANNELBINDING; 'require' rejects an unbound connection with CHANNEL_BINDING_REQUIRED (#1008).
  • Direct TLS on Node.js with sslnegotiation: 'direct' (PostgreSQL 17+) is opened as TLS from the first byte and is the fastest encrypted connection.

... (truncated)

Changelog

Sourced from postgres's changelog.

v4.0.0

v4 rewrites everything below the public API: the pool, the connection, the protocol, startup and the socket layer. Queries, helpers, transactions, cursors, COPY, listen, subscribe, large objects and the options work as in 3.4.9, apart from the changes below.

Security

  • A NUL character in a connection parameter can no longer add parameters (also in v3). A database, user or connection value such as 'db\0user\0postgres' was sent as further startup parameters, so an app that put untrusted input there, as with a database per tenant, could be made to log in as another user where that user needs no password, or with replication or options set. A NUL in any protocol string, also in query text and identifiers, now rejects with NUL_CHARACTER.
  • A column named __proto__ is an own property (also in v3). It became the prototype of the row, so a JSON value in it, for instance from a column alias built from user input, made the row inherit its properties (row.isAdmin), in query results and in sql.subscribe rows alike.

Upgrading from v3

The README has an upgrade guide, with a query that shows whether the change in parameter types concerns you.

  • The server decides the type of every parameter (infer: false by default) (#392). v3 typed a Date as timestamptz, a boolean, a Buffer, a bigint and arrays of these from JavaScript; v4 sends them without a type and writes each value for the type the server asks for, as libpq does. timestamptz columns, values written to a column of their own type, strings, numbers and anything cast work as before. Outside UTC, a Date written to or compared with a timestamp or date column is taken as UTC instead of the session's local time, and a timestamp is read as UTC, so it comes back as the instant that was written whatever the time zone. A Date where the query doesn't decide its type, such as in date_trunc('day', ${ date }), needs a cast (${ date }::timestamptz). infer: true keeps v3's behaviour.
  • Runtimes. Node.js 20 or later, Bun, and Cloudflare Workers; Deno through its Node.js compatibility. The CommonJS and Deno builds are gone: Postgres.js is an ES module, which require can load on Node.js 20.19 and 22.12 and later (require('postgres').default).
  • sql.array() is removed. Pass the array as it is, with a cast where the query doesn't decide its type: ${ ids }::int[]. Calling sql.array() throws ARRAY_REMOVED.
  • A transaction the server rolled back rejects. When the server answers COMMIT with ROLLBACK, sql.begin rejects with TRANSACTION_ROLLED_BACK; v3 took it as a commit.
  • A released connection stays released. A query on a reserved sql after release(), or on a transaction's sql after it has committed or rolled back, rejects; v3 ran it on whatever connection it then had. Releasing a reserved connection while its own BEGIN is still open closes it instead of returning an open transaction to the pool.
  • An unsafe begin outside sql.begin, a reserved connection or max: 1 rejects with UNSAFE_TRANSACTION and is rolled back. A query that looks like it may open a transaction runs alone on its connection, so nothing else lands in it, and any query that leaves its connection in a transaction is rolled back and rejected. v3 rejected BEGIN but left the transaction open. A script that opens and closes its own transaction in one query, such as a migration file with BEGIN and COMMIT, runs; v3 ran it and still rejected it.
  • A query that cannot be built or serialized inside a transaction aborts the transaction, in sql.begin (#1236, #1238) or one opened by hand on a reserved connection, just as a server error would: the queries after it fail with 25P02 and a later COMMIT answers ROLLBACK. v3 skipped the query and let the rest commit.
  • Domains that exist when the pool starts are read and written as their base type, so a domain over int[] comes back as an array of numbers; v3 returned the text.
  • A connection refused for too many connections (53300) is retried with backoff until connect_timeout has passed, and the waiting queries reject with that error only then. Such a refusal is often momentary: connections opened at the same time against a connection limit can all be refused while the server counts them. v3 rejected the queries of the refused connection at once.
  • No host matching target_session_attrs rejects with CONNECTION_DESTROYED instead of retrying forever.
  • An unknown authentication type rejects with AUTH_TYPE_NOT_IMPLEMENTED instead of waiting for the connect timeout.
  • A replication error with no onerror is logged. When the sql.subscribe stream fails and none of its subscriptions has an onerror, the error goes to console.error before the stream reconnects; v3 dropped it. Pass onerror to handle or silence it.
  • infinity timestamps are Infinity and -Infinity, both ways, instead of an invalid Date.
  • TypeScript: the types are an ES module with a default export and named types (import postgres, { type Sql } from 'postgres'). A reserved connection is no longer typed as having begin and end, which it never had.

New

  • Scheduling across connections: when every connection is busy, a query is pipelined on the connection where it should be done soonest, from how long each statement took before and how long what is in flight has run, and slow queries are kept together once the rest of the pool is needed for quick ones. In simulations of mixed workloads, the p99 of quick queries fell 2 to 100 times; on PostgreSQL, a 1 ms lookup no longer waits behind a report on a busy pool (p99.9 from 792 ms to 5 ms). scheduler: false pipelines on the busy connection with the fewest queries in flight instead; v3 went round-robin over the busy connections. With max: 1 it is off, as there is only one connection.
  • queue_timeout: seconds a query, transaction or reserve may wait for a connection before it rejects with QUEUE_TIMEOUT, unsent (#1036, #824).
  • .signal(abortSignal) on a query: aborting rejects it if it is still waiting, or cancels it if it is running.
  • Canceling a cursor between batches stops it. .cancel() or an aborted .signal() while the cursor's callback runs, or while an async iterator over it is between batches, fetches no more rows, closes the portal and rejects with 57014. v3 sent a cancel request that the idle server ignored, so the cursor ran on to the end (or, arriving late, could cancel the next query).
  • sql` and `.join(items) joins fragments and values with a fragment as separator, leaving out falsy items and adding spaces where missing (#807, #813).
  • Nested sql.begin inside a transaction runs in a savepoint (#985).
  • sql.rollback() rolls back a transaction, or the savepoint it is called in, without throwing; sql.begin resolves with the callback's result (#500).
  • Pipelining anywhere in a transaction is documented and tested: queries in a Promise.all between awaited ones are sent together and run in the order they were made (#951).
  • Custom types by name: to and from can be type names, looked up when the pool starts, with array types, for extension types such as pgvector (#1115, #719).
  • using and await using: sql ends the pool and a reserved connection is released when it goes out of scope (#886, #1094).
  • unref_sockets: true lets the process exit while connections are idle, like allowExitOnIdle in node-postgres (#869, #918).
  • min: connections kept open once the pool is used; idle_timeout closes only those above it (#672).
  • user as a function, called each time a connection opens, like password, for credentials that rotate (#881).
  • Password file: with no password given, PGPASSFILE or ~/.pgpass is read as libpq reads it (#964).
  • Named arguments: an object in the parentheses of a function call becomes name => value arguments, make_interval(${ sql({ days: 1 }) }) (#1040).
  • Errors are documented with their fields and how to tell them apart (#1140).
  • COPY row count: a copy ... from stdin writable has count and command once it has finished, with the number of rows the server copied (#465).
  • Persistent replication slots: slot: 'name' keeps the slot of sql.subscribe across restarts and streams from where it was last confirmed. A transaction is confirmed only once its handlers have finished, a handler that fails gets its transaction delivered again, and handlers may be async: they run one after the other in commit order while the stream waits.
  • More from sql.subscribe: truncate events, and the lsn, time and xid of the transaction on every change. Reconnecting retries with backoff.
  • Channel binding: over TLS, SCRAM authenticates with SCRAM-SHA-256-PLUS (tls-server-end-point) when the server offers it, binding the login to the server certificate. channel_binding is 'prefer' by default, 'require' or 'disable' as in libpq, also from the url or PGCHANNELBINDING; 'require' rejects an unbound connection with CHANNEL_BINDING_REQUIRED (#1008).

... (truncated)

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [postgres](https://github.com/porsager/postgres) from 3.4.9 to 4.0.0.
- [Release notes](https://github.com/porsager/postgres/releases)
- [Changelog](https://github.com/porsager/postgres/blob/master/CHANGELOG.md)
- [Commits](porsager/postgres@v3.4.9...v4.0.0)

---
updated-dependencies:
- dependency-name: postgres
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Nov 2, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants