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.
The security fix and the related work
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.



