Skip to main content

Migration from v2

v3 is almost entirely additive — existing code that only uses built-in data types keeps working unchanged. There is exactly one breaking API change, plus two project-level changes you should know about.

Breaking Changes

Custom DataType decode methods renamed

DataType's decode-side members were renamed to pair with their encode* counterparts. This only matters if you registered a custom DataType through GlobalTypeMap (or a DataTypeMap of your own) — built-in types already use the new names.

v2v3
parseBinarydecodeBinary
parseTextdecodeText
parseTextBufferdecodeTextBuffer

The corresponding type aliases were renamed too:

v2v3
ParseTextFunctionDecodeTextFunction
ParseTextBufferFunctionDecodeTextBufferFunction
// v2
const MyType: DataType = {
name: 'my_type',
oid: 90000,
jsType: 'string',
parseBinary(v: Buffer): string {
/* ... */
},
parseText(v: string): string {
/* ... */
},
isType: v => typeof v === 'string',
};

// v3
const MyType: DataType = {
name: 'my_type',
oid: 90000,
jsType: 'string',
decodeBinary(buf: Buffer, offset: number, len: number): string {
/* ... */
},
decodeText(v: string): string {
/* ... */
},
isType: v => typeof v === 'string',
};

decodeBinary's own signature changed again since — see the DataType reference for the current (buf, offset, len, options) shape and the v3.3.0 breaking change that introduced it.

License change: MIT → BSD-3-Clause

v3 relicenses the project from MIT to BSD-3-Clause. Both are permissive licenses; the practical difference is that BSD-3-Clause requires the copyright notice to be preserved in redistributions. Check your organization's license-compliance policy if it tracks dependency licenses. See License.

Node engine bumped to >=20

v3 requires node >= 20.x. See Installation.

New in v3

None of the following requires changes to existing code — all are new, opt-in capabilities:

  • COPY streams — bulk import/export via connection.copyTo() / connection.copyFrom() as Node streams.
  • Large objects — stream data through PostgreSQL's large object API for values too big for bytea.
  • Logical replication — stream row-level changes as they commit.
  • The sql tag — build statements from a template literal instead of hand-rolled string concatenation.
  • Opt-in query pipeliningPool.query() / Pool.execute() can pipeline requests onto a connection, per call.
  • Cancellation and timeouts — pass an AbortSignal to cancel a running query.
  • Multi-host connections — a hosts list with automatic failover and targetSessionAttrs to pick the right server in a cluster.
  • SCRAM channel binding and direct TLS negotiationchannelBinding (default prefer) and sslNegotiation: 'direct' (skips the SSLRequest round trip against PostgreSQL 17+).
  • Two-phase commitprepareTransaction() / commitPrepared().
  • Custom row decoding — a pluggable RowDecoder for taking over how a row's raw wire data becomes a value, e.g. lazy per-cell decoding.

For the full list of fixes and improvements, see the project's CHANGELOG.md.