Fastify v5.9.0 Adds `request.mediaType` and `onMaxParamLength`, Hardens `forwarded` Header Trust, Chunks Large HTTP/2 Replies, and Moves Type Tests to TSTyche

Fastify v5.9.0 Adds `request.mediaType` and `onMaxParamLength`, Hardens `forwarded` Header Trust, Chunks Large HTTP/2 Replies, and Moves Type Tests to TSTyche

lschvn

Fastify v5.9.0, published on 2026-06-28, is the first minor release of the Fastify v5 line in 2026 and a substantial 65-PR cycle. The release's two new public APIs are request.mediaType, a typed accessor for the negotiated media type, and the onMaxParamLength route option, which lets a route hook handle URLs whose single parameter exceeds the configured maxParamLength rather than throwing an FST_ERR_VALIDATION synchronously. The cycle also ships a security fix that no longer trusts X-Forwarded-Host and X-Forwarded-Proto when the incoming socket is missing (#6684 by mcollina), chunks large HTTP/2 buffer replies (#6746), migrates the type-test suite from hand-rolled expect-type assertions to TSTyche (#6532), and adds Node.js 26 to the test matrix while dropping Node.js 20 from the yarn matrix.

The release is the third minor of the v5 line this year. Fastify v5.8.0 shipped on March 5, 2026, and v5.8.5 was the last 5.8.x on April 14, 2026. v5.9.0 is the first one since that 5.8.5 patch that ships a new public API.

The two new public APIs

request.mediaType (climba03003) is the headline feature. Before v5.9.0, application code that wanted to know what media type the client asked for parsed request.headers['accept'] by hand, walked the q-value list, picked the highest match, and then compared to a Content-Type it hoped the route served. The new accessor does the parse and the match in one place. For a req that asked for application/json, the accessor returns 'application/json'; for a req with no Accept header, it returns undefined. The accessor is additive, and the public surface is unchanged. The implementation lives in lib/request.js and the TypeScript surface is exported in fastify.d.ts.

onMaxParamLength (climba03003) is the second. Without the option, Fastify throws an FST_ERR_VALIDATION synchronously when a single URL parameter exceeds the configured maxParamLength (default 100 characters). With the option, the route can do something with the offending request: log a warning, increment a metric, redirect, or return a custom error. The hook is a normal route option ({ onMaxParamLength: (req, reply, maxParamLength) => void }), sitting next to preHandler, onRequest, and the rest of the lifecycle hooks. The change is additive: routes that did not set the option keep the old behavior, and the option is off by default.

PR #6684 (mcollina) closes a request-spoofing gap in the forwarded-header trust path. Before the fix, Fastify would trust the X-Forwarded-Host and X-Forwarded-Proto headers even when the incoming request.socket was missing or undefined (a situation that can happen behind a transport that strips the source connection, or when the request is reconstructed from a parsed body in a test). The new code refuses to read the forwarded headers in that case, falls back to the raw request.host, and surfaces the situation as untrusted input in the TypeScript declaration file via PR #6572 (mcollina), which marks the request metadata accessors (request.ip, request.host, request.protocol, request.ips) with explicit JSDoc warnings that they are not to be trusted for security decisions. The fix is invisible to correctly configured proxies (which always have a real socket on the incoming request) and the change is on the safe side: missing socket means no forwarded header, even if the header is present in the request.

The release also adds useContentType-as-schema-key support so the response schema lookup honors the negotiated content type (#6685 by UlisesGascon), three small hardening commits around routing error codes (#6678) and checkDependencies (#6774), and marks request metadata accessors as untrusted input in the TypeScript declaration file (#6572 by mcollina).

Performance work clusters on the content-type hot path

Three of the four perf entries of the cycle live on the same hot path. PR #6692 (aquie00t) defers the ContentType parse inside getSchemaSerializer until the schema is actually read, #6694 (aquie00t) caches parsed ContentType objects inside the ContentTypeParser, and #6693 (aquie00t) adds a typeof guard in front of toString.call in send and onSendEnd. The fourth is the HTTP/2 buffer-chunking fix (mcollina) for large replies: the old code buffered the entire payload in memory before sending it over the HTTP/2 connection (a 1 GB export meant 1 GB of resident memory on the server); the new code chunks the buffer into smaller pieces and streams them as the HTTP/2 connection can absorb them, so the memory cost is bounded by the chunk size rather than the payload size.

The Vite 8.1 article from June 24 covered a similar shape of perf work in the dev-server build path: a small change on a hot path, repeated across the request lifecycle, that adds up to a noticeable improvement. The Fastify v5.9.0 work is the same idea, on a different runtime.

Trailer, validation, and other fixes

The cycle ships a cluster of fixes around the trailer and validation paths. #6676 (climba03003) prevents a duplicate res.end in sendTrailer when a sync callback fires the trailer, and #6714 (mcollina) ignores duplicate trailer completions. #6678 (mcollina) restores the error.code on routing errors that were silently dropping it, and #6665 (trivikr) allows request.getValidationFunction() to return undefined in the TypeScript declaration, matching the actual runtime behavior. #6753 (LeSingh1) makes hasRequestDecorator and hasReplyDecorator catch constructor-assigned built-in properties that were previously missed, which closes a long-standing gap where the decorators were wrongly reported as not present on a request or reply that had been wrapped by a built-in.

The release also ships a Node.js test-matrix bump. #6728 (Fdawgs) adds Node.js 26 to the test matrix, which lines up with the Node.js 26.4.0 release on June 25, and #6662 (Tony133) drops Node.js 20 from the yarn CI matrix, which is consistent with the Node.js project's End-of-Life schedule for Node.js 20 and with the Deno 2.9 article from June 26 covering the runtime landscape.

TSTyche for type tests, fastify-plugin v6.0.0

The migration of Fastify's type-test suite from hand-rolled expect-type assertions to TSTyche is the most interesting infrastructure change of the cycle. PR #6532 (mrazauskas) introduces TSTyche, and #6726 and #6727 finish the migration in two batches. TSTyche is a purpose-built type-test runner that runs at TypeScript's compile step rather than at runtime, and that gives better diagnostics when an assertion fails (the failure points at the line and the expected vs. actual type, rather than a runtime false from expect-type). The change is invisible to Fastify users; it speeds up the maintainers' CI and gives them better error messages when a type test fails.

The release also pins a fastify-plugin bump from 5.1.0 to 6.0.0 (#6801). fastify-plugin is a TypeScript-only peer of Fastify; v6.0.0 is a major version bump that drops some of the older CommonJS-style code paths and aligns the API surface with the v5 Fastify line. The bump is on a dependencies line that plugin authors consume via peerDependencies; application code that uses Fastify directly is unaffected.

Why this matters

Fastify v5.9.0 is the release where the framework is mid-way through a year-long hardening cycle. The v5.0 line shipped in late 2024 and the project has been steadily adding type-safe accessors, hardening the forwarded-header trust path, and migrating the test infrastructure to tools that are a better fit for the codebase. v5.9.0 is the first release in that cycle that ships both a new public API and a security-relevant fix, which is the pattern that makes a minor worth writing about.

For application developers the practical change is small and concrete. The two new public APIs are additive and the security fix is on the safe side. The TypeScript surface gets a new accessor and the request metadata accessors are explicitly marked as untrusted input, which is the right thing to do and the right time to do it. The HTTP/2 buffer-chunking fix is invisible to small payloads and significant for very large ones, which is the shape of fix that matters for a route that serves a generated binary blob.

For the wider Node.js web framework space, Fastify v5.9.0 lines up with the Bun runtime updates and the Deno 2.9 release notes to show that the three major JavaScript runtimes are all hardening their HTTP and request-handling paths in parallel. Fastify is the framework-level counterpart to those runtime-level changes.

Frequently Asked Questions

npm 11.18 Promotes the `linked` Install Strategy to Stable, Adds the `npm install-scripts` Namespace, and Warns When `min-release-age` Blocks an Audit Fix

npm 11.18.0 (June 29, 2026) ships three features and a long backlog of bug fixes that together finish the work the npm CLI has been doing on the `install-strategy=linked` (isolated) install mode since RFC #0042 in 2022. The headline is [PR #9677](https://github.com/npm/cli/pull/9677) (backport of #9674), which graduates `--install-strategy=linked` from experimental to stable. The mode installs every package into `node_modules/.store/<name>@<version>/node_modules/<dep>` and links each into its parent's `node_modules` tree, so a package can only `require` dependencies that are actually declared in its own `package.json`. The new docs recommendation ([PR #9690](https://github.com/npm/cli/pull/9690)) is to run `--install-strategy=linked` in CI to catch phantom dependencies before publishing. Around the graduation the release ships a namespaced `npm install-scripts` command ([#9635](https://github.com/npm/cli/pull/9635), backport of #9629) that owns `approve`, `deny`, and `ls`, with `npm approve-scripts` / `npm deny-scripts` kept as aliases; an `install-scripts: prune unused allowScripts entries` housekeeping pass ([#9662](https://github.com/npm/cli/pull/9662)); and a new warning when `min-release-age` blocks an `npm audit fix` ([#9564](https://github.com/npm/cli/pull/9564)). The 43-commit release also fixes 19 `linked` strategy bugs (audit determinism #9638, dangling `.bin` shims #9643, stale `.store` cleanup #9649, invalid `filterNode` crash #9645, peerOptional validation #9641), three `npm sbom` fixes, and a percent-encoded `vcs_url` purl fix ([#9693](https://github.com/npm/cli/pull/9693)).

Claude Sonnet 5 Goes Default in Claude Code 2.1.197 with a 1M-Token Context Window, $2/$10 Per Mtok Introductory Pricing, and Cyber Safeguards On by Default

Anthropic announced Claude Sonnet 5 on 2026-06-30 ([Introducing Claude Sonnet 5](https://www.anthropic.com/news/claude-sonnet-5)), and Claude Code [v2.1.197](https://github.com/anthropics/claude-code/releases/tag/v2.1.197) (released the same day) made it the default model. The launch is the first Sonnet-line model that closes the agentic gap with Opus 4.8, ships a native 1M-token context window, and lands on introductory pricing of $2 per million input tokens and $10 per million output tokens through August 31, 2026 (then $3/$15 per Mtok). Sonnet 5 is the new default for Free and Pro plans in Claude and is the default model in Claude Code, available immediately on update. The release ships with cyber safeguards enabled by default (the same safeguards as Opus 4.7 and 4.8, less strict than the Fable 5 set), a refreshed tokenizer that inflates token counts 1.0 to 1.35x, and rate-limit increases across Chat, Cowork, Claude Code, and the Claude Platform to absorb the higher token usage of the new effort-level controls. The Anthropic system card and the Claude Code release notes both ship the same day, so the Claude Code audience gets the new model the same day it is announced.

Related articles

More coverage with overlapping topics and tags.

Deno 2.9 Ships 1.98x Faster Cold Start, 2.2-3.1x Less RSS Under Load, Default-On npm Minimum Release Age, No-Downgrade Trust Policy, and Built-In Snapshot Testing
runtimes

Deno 2.9 Ships 1.98x Faster Cold Start, 2.2-3.1x Less RSS Under Load, Default-On npm Minimum Release Age, No-Downgrade Trust Policy, and Built-In Snapshot Testing

Deno 2.9 (Bartek Iwańczuk, published 2026-06-25 on deno.com/blog/v2.9) is the largest Deno release of the cycle. Cold start drops from 34.2 ms to 17.3 ms (1.98x), peak RSS on the Deno.serve realworld workload drops 2.2x (142 MB → 64 MB) and 3.1x on 1 MiB bodies (197 MB → 63 MB), and Deno.serve throughput climbs 1.27x realworld (56.8k → 72.4k req/s), 1.11x plaintext, and 1.18x on 1 MiB bodies. Supply chain hardening: npm minimum-release-age is enabled by default with a 24h window (PR #35458), and a new opt-in no-downgrade trust policy (PR #34927) refuses to resolve any version whose trust evidence (staged publish, trusted publishing, provenance attestation) is weaker than the strongest evidence on any earlier-published version of the same package. Test runner parity: built-in t.assertSnapshot() (#35139), Deno.test.each (#34938), --shard for CI fan-out (#35057), retry and repeats (#35053), change-aware --changed and --related (#35199), and coverage thresholds (#35056). Lockfile interop: deno install seeds deno.lock from package-lock.json, pnpm-lock.yaml, yarn.lock, or bun.lock (#34296, #35330, #35346, #35350, #35394), pnpm-workspace.yaml auto-migrates to deno.json / package.json (#34993), and git merge conflict markers in deno.lock auto-resolve (#34726). Plus: deno desktop graduates from experimental (the June 16 PR #33441), deno link / deno unlink / deno list / deno watch subcommands, stable --unsafe-proto (#34738), Web Locks API (#31166), Happy Eyeballs v2 (RFC 8305) (#31726), navigator.userAgentData (#34743), the WebCrypto Modern Algorithms proposal (ML-KEM, ML-DSA, SLH-DSA, ChaCha20-Poly1305, SHA-3 family, KMAC, Argon2) (#34447, #34448, #34914, #35223), Node 26.3.0 compat (#34746, #34747), Node-API v10 (#35270), and CSS module imports under --unstable-raw-imports (#35093). 165+ PRs land in this cycle.
Node.js 26.4.0 'Current' Ships node:vfs Subsystem (Matteo Collina), ESM Loader Package Maps (Maël Nison), TLS Certificate Compression, TCP_KEEPINTVL/TCP_KEEPCNT, and argon2 Stable
runtimes

Node.js 26.4.0 'Current' Ships node:vfs Subsystem (Matteo Collina), ESM Loader Package Maps (Maël Nison), TLS Certificate Compression, TCP_KEEPINTVL/TCP_KEEPCNT, and argon2 Stable

Node.js 26.4.0 (Current), published 2026-06-24 by @aduh95, lands eight SEMVER-MINOR changes: a minimal node:vfs subsystem that mounts user-supplied virtual filesystems (PR #63115, Matteo Collina) plus a follow-up that dispatches node:fs/promises to mounted VFS instances (PR #63537), package maps for ESM loaders that route bare specifiers through the loader hooks (PR #62239, Maël Nison), TLS certificateCompression that wires RFC 8879 zlib and zstd compression through the OpenSSL build config (PR #62217, Tim Perry), TCP_KEEPINTVL and TCP_KEEPCNT support in net.Socket.setKeepAlive (PR #63825, Guy Bedford), caller-supplied buffers in fs.readFile / fs.readFileSync (PR #63634, Matteo Collina), closeIdleConnections that now also drops pre-request sockets (PR #63470, semimikoh), net.BlockList advanced to Release Candidate stability (PR #63050), and crypto argon2 + KEM encap/decap marked stable (PR #63924, Filip Skokan). The release also adds WebCrypto cSHAKE (PR #63988), QUIC listEndpoints (PR #63536) and X509Certificate handles (PR #63191), dgram connectSync / bindSync (PRs #63838 + #63932, Guy Bedford), early-TCP net.BoundSocket (PR #63951), an experimental fast FFI call path for AArch64 and x86_64 (PRs #63068 + #63941, Paolo Insogna), npm 11.17.0 (PR #63857), sqlite 3.53.2, and libffi 3.6.0.
Node.js 24.18.0 'Krypton' LTS Lands Buffer.poolSize at 64 KiB, Web Crypto's TurboSHAKE and KangarooTwelve, and http.writeInformation for Arbitrary 1xx Codes
runtimes

Node.js 24.18.0 'Krypton' LTS Lands Buffer.poolSize at 64 KiB, Web Crypto's TurboSHAKE and KangarooTwelve, and http.writeInformation for Arbitrary 1xx Codes

Node.js 24.18.0 'Krypton' (LTS), published 2026-06-23, ships the Buffer.poolSize 64 KiB default that landed on Current in 26.3.0, adds RFC 9861's TurboSHAKE and KangarooTwelve to Web Cryptography (PR #62183, 1,521 additions, 13 files), adds http.writeInformation for arbitrary 1xx status codes (PR #63155, 306 additions, 7 files), exposes V8 precise coverage start to the JS inspector runtime (commit 8c989ec4a3), adds JWK import-export for the ML-KEM and SLH-DSA post-quantum key types (PR #62706, 842 additions, 39 files), lands the BoringSSL-side wiring of ML-DSA, ML-KEM, ChaCha20-Poly1305, and AES-KW for Web Crypto (PR #63255), hardens WebCrypto against prototype pollution (PR #63363), aligns crypto.diffieHellman key argument names and accepts key data inputs (PR #62527), reverts the 24.16.0 'noop pause/resume on destroyed streams' behavior (PR #63834), and ships a single-line hotfix on 22.23.1 that backs out an http agent change from the 06-18 security release that triggered an unexpected re-stream.

Comments

Log in Log in to join the conversation.

No comments yet. Be the first to share your thoughts.