Skip to content

fix: keep the default response encoding stable across Node.js versions#403

Open
rxits wants to merge 1 commit into
fastify:mainfrom
rxits:fix/stable-default-encoding-369
Open

fix: keep the default response encoding stable across Node.js versions#403
rxits wants to merge 1 commit into
fastify:mainfrom
rxits:fix/stable-default-encoding-369

Conversation

@rxits

@rxits rxits commented Jun 14, 2026

Copy link
Copy Markdown

Fixes #369

Regression

Since v8.1.0, the default response compression changes based on the Node.js version: under Node.js < 22.15 the default is br, but under Node.js ≥ 22.15 (where zlib.createZstdCompress exists) the same app defaults to zstd. Upgrading Node silently changes the wire format, which breaks consumers that don't expect/recognize zstd.

Cause

processCompressParams / processDecompressParams build the supported-encodings list and then unshift('zstd') to the front whenever the runtime supports it:

const supportedEncodings = ['br', 'gzip', 'deflate', 'identity']
if (typeof zlib.createZstdCompress === 'function') {
  supportedEncodings.unshift('zstd')   // zstd becomes the top server preference
}

@fastify/accept-negotiator uses this order to break ties, so a normal client sending Accept-Encoding: gzip, deflate, br, zstd now negotiates zstd instead of br.

Fix

Insert zstd before identity rather than at the front, so br stays the negotiated default (matching pre-8.1.0 behavior) while zstd is still offered when a client explicitly prefers it. identity remains last. Applied to both the compress and decompress encoding lists.

Tests

Added a test asserting that a client accepting gzip, deflate, br, zstd gets br (not zstd) on a zstd-capable runtime. Verified failing before the fix (expected 'br', actual 'zstd') and passing after. Full unit suite: 174/174 pass, lint clean. The existing explicit-zstd and wildcard (* → gzip) tests are unaffected.

zstd was unshifted to the front of the supported-encodings list whenever
the runtime exposed zlib.createZstdCompress (Node.js >= 22.15), which made
it the negotiated default. The same app therefore switched its default
compression from br to zstd purely by upgrading Node, breaking consumers
that don't expect zstd.

Insert zstd before identity instead of at the front, so br stays the
negotiated default while zstd remains available when a client explicitly
prefers it. Applied to both the compress and decompress encoding lists.

Fixes fastify#369
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default compression silently changes when running under new Node version

1 participant