# Table of Contents
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [Introduction | Fastify](#introduction-fastify)
- [LTS | Fastify](#lts-fastify)
- [Getting-Started | Fastify](#getting-started-fastify)
- [Index | Fastify](#index-fastify)
- [Index | Fastify](#index-fastify)
- [Benchmarking | Fastify](#benchmarking-fastify)
- [Benchmarking | Fastify](#benchmarking-fastify)
- [LTS | Fastify](#lts-fastify)
- [LTS | Fastify](#lts-fastify)
- [LTS | Fastify](#lts-fastify)
- [LTS | Fastify](#lts-fastify)
- [Lifecycle | Fastify](#lifecycle-fastify)
- [HTTP2 | Fastify](#http2-fastify)
- [Encapsulation | Fastify](#encapsulation-fastify)
- [HTTP2 | Fastify](#http2-fastify)
- [Middleware | Fastify](#middleware-fastify)
- [Technical Principles | Fastify](#technical-principles-fastify)
- [Encapsulation | Fastify](#encapsulation-fastify)
- [Plugins | Fastify](#plugins-fastify)
- [ContentTypeParser | Fastify](#contenttypeparser-fastify)
- [ContentTypeParser | Fastify](#contenttypeparser-fastify)
- [Logging | Fastify](#logging-fastify)
- [Lifecycle | Fastify](#lifecycle-fastify)
- [Errors | Fastify](#errors-fastify)
- [Errors | Fastify](#errors-fastify)
- [Decorators | Fastify](#decorators-fastify)
- [Request | Fastify](#request-fastify)
- [Decorators | Fastify](#decorators-fastify)
- [Logging | Fastify](#logging-fastify)
- [Middleware | Fastify](#middleware-fastify)
- [Technical Principles | Fastify](#technical-principles-fastify)
- [Plugins | Fastify](#plugins-fastify)
- [Type-Providers | Fastify](#type-providers-fastify)
- [Hooks | Fastify](#hooks-fastify)
- [Reply | Fastify](#reply-fastify)
- [Hooks | Fastify](#hooks-fastify)
- [Routes | Fastify](#routes-fastify)
- [Reply | Fastify](#reply-fastify)
- [TypeScript | Fastify](#typescript-fastify)
- [Validation-and-Serialization | Fastify](#validation-and-serialization-fastify)
- [Server | Fastify](#server-fastify)
- [Request | Fastify](#request-fastify)
- [Warnings | Fastify](#warnings-fastify)
- [Routes | Fastify](#routes-fastify)
- [Type-Providers | Fastify](#type-providers-fastify)
- [TypeScript | Fastify](#typescript-fastify)
- [Warnings | Fastify](#warnings-fastify)
- [Validation-and-Serialization | Fastify](#validation-and-serialization-fastify)
- [Server | Fastify](#server-fastify)
- [ContentTypeParser | Fastify](#contenttypeparser-fastify)
- [Decorators | Fastify](#decorators-fastify)
- [Encapsulation | Fastify](#encapsulation-fastify)
- [Errors | Fastify](#errors-fastify)
- [HTTP2 | Fastify](#http2-fastify)
- [Hooks | Fastify](#hooks-fastify)
- [Lifecycle | Fastify](#lifecycle-fastify)
- [Logging | Fastify](#logging-fastify)
- [Middleware | Fastify](#middleware-fastify)
- [Plugins | Fastify](#plugins-fastify)
- [Technical Principles | Fastify](#technical-principles-fastify)
- [Reply | Fastify](#reply-fastify)
- [ContentTypeParser | Fastify](#contenttypeparser-fastify)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/latest/#__docusaurus_skipToContent_fallback)
Version: latest (v5.4.x)
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/latest/Reference/)
* [Guides](https://fastify.dev/docs/latest/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/latest/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/latest/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/latest/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/latest/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/latest/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/latest/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/latest/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v5.4.x/Reference/)
* [Guides](https://fastify.dev/docs/v5.4.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v5.4.x/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v5.4.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v5.4.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v5.4.x/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v5.4.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v5.4.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v5.4.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v5.3.x/Reference/)
* [Guides](https://fastify.dev/docs/v5.3.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v5.3.x/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v5.3.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v5.3.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v5.3.x/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v5.3.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v5.3.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v5.3.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v5.1.x/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
Version: v5.1.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v5.1.x/Reference/)
* [Guides](https://fastify.dev/docs/v5.1.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v5.1.x/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v5.1.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v5.1.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v5.1.x/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v5.1.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v5.1.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v5.1.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v5.2.x/Reference/)
* [Guides](https://fastify.dev/docs/v5.2.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v5.2.x/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v5.2.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v5.2.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v5.2.x/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v5.2.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v5.2.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v5.2.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v5.0.x/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
Version: v5.0.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v5.0.x/Reference/)
* [Guides](https://fastify.dev/docs/v5.0.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v5.0.x/#where-to-start "Direct link to Where To Start")
---------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v5.0.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v5.0.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v5.0.x/#additional-documentation "Direct link to Additional Documentation")
---------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v5.0.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v5.0.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v5.0.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v4.29.x/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
Version: v4.29.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v4.29.x/Reference/)
* [Guides](https://fastify.dev/docs/v4.29.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal educational style as a means to introduce newcomers to core and advanced Fastify concepts.
Where To Start[](https://fastify.dev/docs/v4.29.x/#where-to-start "Direct link to Where To Start")
----------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v4.29.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v4.29.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v4.29.x/#additional-documentation "Direct link to Additional Documentation")
----------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v4.29.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v4.29.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v4.29.x/#additional-documentation)
---
# Introduction | Fastify
[Skip to main content](https://fastify.dev/docs/v3.29.x/#__docusaurus_skipToContent_fallback)
This is documentation for Fastify **v3.29.x**, which is no longer actively maintained.
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
For information about support options for end-of-life versions, see the [Long Term Support](https://fastify.dev/docs/latest/Reference/LTS)
page.
Version: v3.29.x
On this page
The documentation for Fastify is split into two categories:
* [Reference documentation](https://fastify.dev/docs/v3.29.x/Reference/)
* [Guides](https://fastify.dev/docs/v3.29.x/Guides/)
The reference documentation utilizes a very formal style in an effort to document Fastify's API and implementation details thoroughly for the developer who needs such. The guides category utilizes an informal, educational, style as a means to introduce newcomers to core, and advanced, Fastify concepts.
Where To Start[](https://fastify.dev/docs/v3.29.x/#where-to-start "Direct link to Where To Start")
----------------------------------------------------------------------------------------------------
Complete newcomers to Fastify should first read our [Getting Started](https://fastify.dev/docs/v3.29.x/Guides/Getting-Started/)
guide.
Developers experienced with Fastify should consult the [reference documentation](https://fastify.dev/docs/v3.29.x/Reference/)
directly to find the topic they are seeking more information about.
Additional Documentation[](https://fastify.dev/docs/v3.29.x/#additional-documentation "Direct link to Additional Documentation")
----------------------------------------------------------------------------------------------------------------------------------
* Fastify's [Long Term Support (LTS)](https://fastify.dev/docs/v3.29.x/Reference/LTS/)
policy
* [Where To Start](https://fastify.dev/docs/v3.29.x/#where-to-start)
* [Additional Documentation](https://fastify.dev/docs/v3.29.x/#additional-documentation)
---
# LTS | Fastify
[Skip to main content](https://fastify.dev/docs/latest/Reference/LTS/#__docusaurus_skipToContent_fallback)
Version: latest (v5.4.x)
On this page
Long Term Support[](https://fastify.dev/docs/latest/Reference/LTS/#long-term-support "Direct link to Long Term Support")
--------------------------------------------------------------------------------------------------------------------------
Fastify's Long Term Support (LTS) is provided according to the schedule laid out in this document:
1. Major releases, "X" release of [semantic versioning](https://semver.org/)
X.Y.Z release versions, are supported for a minimum period of six months from their release date. The release date of any specific version can be found at [https://github.com/fastify/fastify/releases](https://github.com/fastify/fastify/releases)
.
2. Major releases will receive security updates for an additional six months from the release of the next major release. After this period we will still review and release security fixes as long as they are provided by the community and they do not violate other constraints, e.g. minimum supported Node.js version.
3. Major releases will be tested and verified against all Node.js release lines that are supported by the [Node.js LTS policy](https://github.com/nodejs/Release)
within the LTS period of that given Fastify release line. This implies that only the latest Node.js release of a given line is supported.
4. In addition to Node.js runtime, major releases of Fastify will also be tested and verified against alternative runtimes that are compatible with Node.js. The maintenance teams of these alternative runtimes are responsible for ensuring and guaranteeing these tests work properly.
1. [N|Solid](https://docs.nodesource.com/docs/product_suite)
tests and verifies each Fastify major release against current N|Solid LTS versions. NodeSource ensures Fastify compatibility with N|Solid, aligning with the support scope of N|Solid LTS versions at the time of the Fastify release. This guarantees N|Solid users can confidently use Fastify.
A "month" is defined as 30 consecutive days.
> Security Releases and Semver[](https://fastify.dev/docs/latest/Reference/LTS/#security-releases-and-semver "Direct link to Security Releases and Semver")
>
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
> As a consequence of providing long-term support for major releases, there are occasions where we need to release breaking changes as a _minor_ version release. Such changes will _always_ be noted in the [release notes](https://github.com/fastify/fastify/releases)
> .
>
> To avoid automatically receiving breaking security updates it is possible to use the tilde (`~`) range qualifier. For example, to get patches for the 3.15 release, and avoid automatically updating to the 3.16 release, specify the dependency as `"fastify": "~3.15.x"`. This will leave your application vulnerable, so please use it with caution.
### Security Support Beyond LTS[](https://fastify.dev/docs/latest/Reference/LTS/#security-support-beyond-lts "Direct link to Security Support Beyond LTS")
Fastify's partner, HeroDevs, provides commercial security support through the OpenJS Ecosystem Sustainability Program for versions of Fastify that are EOL. For more information, see their [Never Ending Support](https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=eol_support_fastify)
service.
### Schedule[](https://fastify.dev/docs/latest/Reference/LTS/#schedule "Direct link to Schedule")
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
### CI tested operating systems[](https://fastify.dev/docs/latest/Reference/LTS/#ci-tested-operating-systems "Direct link to CI tested operating systems")
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)
for further details on what the latest virtual environment is in relation to the YAML workflow labels below:
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
| Windows | `windows-latest` | npm | 20 | v5(20) |
| MacOS | `macos-latest` | npm | 20 | v5(20) |
Using [yarn](https://yarnpkg.com/)
might require passing the `--ignore-engines` flag.
* [Long Term Support](https://fastify.dev/docs/latest/Reference/LTS/#long-term-support)
* [Security Releases and Semver](https://fastify.dev/docs/latest/Reference/LTS/#security-releases-and-semver)
* [Security Support Beyond LTS](https://fastify.dev/docs/latest/Reference/LTS/#security-support-beyond-lts)
* [Schedule](https://fastify.dev/docs/latest/Reference/LTS/#schedule)
* [CI tested operating systems](https://fastify.dev/docs/latest/Reference/LTS/#ci-tested-operating-systems)
---
# Getting-Started | Fastify
[Skip to main content](https://fastify.dev/docs/latest/Guides/Getting-Started/#__docusaurus_skipToContent_fallback)
Version: latest (v5.4.x)
On this page
Getting Started[](https://fastify.dev/docs/latest/Guides/Getting-Started/#getting-started "Direct link to Getting Started")
-----------------------------------------------------------------------------------------------------------------------------
Hello! Thank you for checking out Fastify!
This document aims to be a gentle introduction to the framework and its features. It is an elementary preface with examples and links to other parts of the documentation.
Let's start!
### Install[](https://fastify.dev/docs/latest/Guides/Getting-Started/#install "Direct link to Install")
Install with npm:
npm i fastify
Install with yarn:
yarn add fastify
### Your first server[](https://fastify.dev/docs/latest/Guides/Getting-Started/#your-first-server "Direct link to Your first server")
Let's write our first server:
// Require the framework and instantiate it// ESMimport Fastify from 'fastify'const fastify = Fastify({ logger: true})// CommonJsconst fastify = require('fastify')({ logger: true})// Declare a routefastify.get('/', function (request, reply) { reply.send({ hello: 'world' })})// Run the server!fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
> If you are using ECMAScript Modules (ESM) in your project, be sure to include "type": "module" in your package.json.
>
> { "type": "module"}
Do you prefer to use `async/await`? Fastify supports it out-of-the-box.
// ESMimport Fastify from 'fastify'const fastify = Fastify({ logger: true})// CommonJsconst fastify = require('fastify')({ logger: true})fastify.get('/', async (request, reply) => { return { hello: 'world' }})/** * Run the server! */const start = async () => { try { await fastify.listen({ port: 3000 }) } catch (err) { fastify.log.error(err) process.exit(1) }}start()
Awesome, that was easy.
Unfortunately, writing a complex application requires significantly more code than this example. A classic problem when you are building a new application is how to handle multiple files, asynchronous bootstrapping, and the architecture of your code.
Fastify offers an easy platform that helps to solve all of the problems outlined above, and more!
> **Note** The above examples, and subsequent examples in this document, default to listening _only_ on the localhost `127.0.0.1` interface. To listen on all available IPv4 interfaces the example should be modified to listen on `0.0.0.0` like so:
>
> fastify.listen({ port: 3000, host: '0.0.0.0' }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } fastify.log.info(`server listening on ${address}`)})
>
> Similarly, specify `::1` to accept only local connections via IPv6. Or specify `::` to accept connections on all IPv6 addresses, and, if the operating system supports it, also on all IPv4 addresses.
>
> When deploying to a Docker (or another type of) container using `0.0.0.0` or `::` would be the easiest method for exposing the application.
>
> Note that when using `0.0.0.0`, the address provided in the callback argument above will be the first address the wildcard refers to.
### Your first plugin[](https://fastify.dev/docs/latest/Guides/Getting-Started/#your-first-plugin "Direct link to Your first plugin")
As with JavaScript, where everything is an object, with Fastify everything is a plugin.
Before digging into it, let's see how it works!
Let's declare our basic server, but instead of declaring the route inside the entry point, we'll declare it in an external file (check out the [route declaration](https://fastify.dev/docs/latest/Reference/Routes/)
docs).
// ESMimport Fastify from 'fastify'import firstRoute from './our-first-route.js'/** * @type {import('fastify').FastifyInstance} Instance of Fastify */const fastify = Fastify({ logger: true})fastify.register(firstRoute)fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
// CommonJs/** * @type {import('fastify').FastifyInstance} Instance of Fastify */const fastify = require('fastify')({ logger: true})fastify.register(require('./our-first-route'))fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
// our-first-route.js/** * Encapsulates the routes * @param {FastifyInstance} fastify Encapsulated Fastify Instance * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options */async function routes (fastify, options) { fastify.get('/', async (request, reply) => { return { hello: 'world' } })}//ESMexport default routes;// CommonJsmodule.exports = routes
In this example, we used the `register` API, which is the core of the Fastify framework. It is the only way to add routes, plugins, et cetera.
At the beginning of this guide, we noted that Fastify provides a foundation that assists with asynchronous bootstrapping of your application. Why is this important?
Consider the scenario where a database connection is needed to handle data storage. The database connection needs to be available before the server is accepting connections. How do we address this problem?
A typical solution is to use a complex callback, or promises - a system that will mix the framework API with other libraries and the application code.
Fastify handles this internally, with minimum effort!
Let's rewrite the above example with a database connection.
First, install `fastify-plugin` and `@fastify/mongodb`:
npm i fastify-plugin @fastify/mongodb
**server.js**
// ESMimport Fastify from 'fastify'import dbConnector from './our-db-connector.js'import firstRoute from './our-first-route.js'/** * @type {import('fastify').FastifyInstance} Instance of Fastify */const fastify = Fastify({ logger: true})fastify.register(dbConnector)fastify.register(firstRoute)fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
// CommonJs/** * @type {import('fastify').FastifyInstance} Instance of Fastify */const fastify = require('fastify')({ logger: true})fastify.register(require('./our-db-connector'))fastify.register(require('./our-first-route'))fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
**our-db-connector.js**
// ESMimport fastifyPlugin from 'fastify-plugin'import fastifyMongo from '@fastify/mongodb'/** * @param {FastifyInstance} fastify * @param {Object} options */async function dbConnector (fastify, options) { fastify.register(fastifyMongo, { url: 'mongodb://localhost:27017/test_database' })}// Wrapping a plugin function with fastify-plugin exposes the decorators// and hooks, declared inside the plugin to the parent scope.export default fastifyPlugin(dbConnector)
// CommonJs/** * @type {import('fastify-plugin').FastifyPlugin} */const fastifyPlugin = require('fastify-plugin')/** * Connects to a MongoDB database * @param {FastifyInstance} fastify Encapsulated Fastify Instance * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options */async function dbConnector (fastify, options) { fastify.register(require('@fastify/mongodb'), { url: 'mongodb://localhost:27017/test_database' })}// Wrapping a plugin function with fastify-plugin exposes the decorators// and hooks, declared inside the plugin to the parent scope.module.exports = fastifyPlugin(dbConnector)
**our-first-route.js**
/** * A plugin that provide encapsulated routes * @param {FastifyInstance} fastify encapsulated fastify instance * @param {Object} options plugin options, refer to https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options */async function routes (fastify, options) { const collection = fastify.mongo.db.collection('test_collection') fastify.get('/', async (request, reply) => { return { hello: 'world' } }) fastify.get('/animals', async (request, reply) => { const result = await collection.find().toArray() if (result.length === 0) { throw new Error('No documents found') } return result }) fastify.get('/animals/:animal', async (request, reply) => { const result = await collection.findOne({ animal: request.params.animal }) if (!result) { throw new Error('Invalid value') } return result }) const animalBodyJsonSchema = { type: 'object', required: ['animal'], properties: { animal: { type: 'string' }, }, } const schema = { body: animalBodyJsonSchema, } fastify.post('/animals', { schema }, async (request, reply) => { // we can use the `request.body` object to get the data sent by the client const result = await collection.insertOne({ animal: request.body.animal }) return result })}module.exports = routes
Wow, that was fast!
Let's recap what we have done here since we've introduced some new concepts.
As you can see, we used `register` for both the database connector and the registration of the routes.
This is one of the best features of Fastify, it will load your plugins in the same order you declare them, and it will load the next plugin only once the current one has been loaded. In this way, we can register the database connector in the first plugin and use it in the second _(read [here](https://fastify.dev/docs/latest/Reference/Plugins/#handle-the-scope)
to understand how to handle the scope of a plugin)_.
Plugin loading starts when you call `fastify.listen()`, `fastify.inject()` or `fastify.ready()`
The MongoDB plugin uses the `decorate` API to add custom objects to the Fastify instance, making them available for use everywhere. Use of this API is encouraged to facilitate easy code reuse and to decrease code or logic duplication.
To dig deeper into how Fastify plugins work, how to develop new plugins, and for details on how to use the whole Fastify API to deal with the complexity of asynchronously bootstrapping an application, read [the hitchhiker's guide to plugins](https://fastify.dev/docs/latest/Guides/Plugins-Guide/)
.
### Loading order of your plugins[](https://fastify.dev/docs/latest/Guides/Getting-Started/#loading-order-of-your-plugins "Direct link to Loading order of your plugins")
To guarantee consistent and predictable behavior of your application, we highly recommend to always load your code as shown below:
└── plugins (from the Fastify ecosystem)└── your plugins (your custom plugins)└── decorators└── hooks└── your services
In this way, you will always have access to all of the properties declared in the current scope.
As discussed previously, Fastify offers a solid encapsulation model, to help you build your application as independent services. If you want to register a plugin only for a subset of routes, you just have to replicate the above structure.
└── plugins (from the Fastify ecosystem)└── your plugins (your custom plugins)└── decorators└── hooks└── your services │ └── service A │ └── plugins (from the Fastify ecosystem) │ └── your plugins (your custom plugins) │ └── decorators │ └── hooks │ └── your services │ └── service B └── plugins (from the Fastify ecosystem) └── your plugins (your custom plugins) └── decorators └── hooks └── your services
### Validate your data[](https://fastify.dev/docs/latest/Guides/Getting-Started/#validate-your-data "Direct link to Validate your data")
Data validation is extremely important and a core concept of the framework.
To validate incoming requests, Fastify uses [JSON Schema](https://json-schema.org/)
.
Let's look at an example demonstrating validation for routes:
/** * @type {import('fastify').RouteShorthandOptions} * @const */const opts = { schema: { body: { type: 'object', properties: { someKey: { type: 'string' }, someOtherKey: { type: 'number' } } } }}fastify.post('/', opts, async (request, reply) => { return { hello: 'world' }})
This example shows how to pass an options object to the route, which accepts a `schema` key that contains all of the schemas for route, `body`, `querystring`, `params`, and `headers`.
Read [Validation and Serialization](https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/)
to learn more.
### Serialize your data[](https://fastify.dev/docs/latest/Guides/Getting-Started/#serialize-your-data "Direct link to Serialize your data")
Fastify has first-class support for JSON. It is extremely optimized to parse JSON bodies and serialize JSON output.
To speed up JSON serialization (yes, it is slow!) use the `response` key of the schema option as shown in the following example:
/** * @type {import('fastify').RouteShorthandOptions} * @const */const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }}fastify.get('/', opts, async (request, reply) => { return { hello: 'world' }})
By specifying a schema as shown, you can speed up serialization by a factor of 2-3. This also helps to protect against leakage of potentially sensitive data, since Fastify will serialize only the data present in the response schema. Read [Validation and Serialization](https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/)
to learn more.
### Parsing request payloads[](https://fastify.dev/docs/latest/Guides/Getting-Started/#parsing-request-payloads "Direct link to Parsing request payloads")
Fastify parses `'application/json'` and `'text/plain'` request payloads natively, with the result accessible from the [Fastify request](https://fastify.dev/docs/latest/Reference/Request/)
object at `request.body`.
The following example returns the parsed body of a request back to the client:
/** * @type {import('fastify').RouteShorthandOptions} */const opts = {}fastify.post('/', opts, async (request, reply) => { return request.body})
Read [Content-Type Parser](https://fastify.dev/docs/latest/Reference/ContentTypeParser/)
to learn more about Fastify's default parsing functionality and how to support other content types.
### Extend your server[](https://fastify.dev/docs/latest/Guides/Getting-Started/#extend-your-server "Direct link to Extend your server")
Fastify is built to be extremely extensible and minimal, we believe that a bare-bones framework is all that is necessary to make great applications possible.
In other words, Fastify is not a "batteries included" framework, and relies on an amazing [ecosystem](https://fastify.dev/docs/latest/Guides/Ecosystem/)
!
### Test your server[](https://fastify.dev/docs/latest/Guides/Getting-Started/#test-your-server "Direct link to Test your server")
Fastify does not offer a testing framework, but we do recommend a way to write your tests that uses the features and architecture of Fastify.
Read the [testing](https://fastify.dev/docs/latest/Guides/Testing/)
documentation to learn more!
### Run your server from CLI[](https://fastify.dev/docs/latest/Guides/Getting-Started/#run-your-server-from-cli "Direct link to Run your server from CLI")
Fastify also has CLI integration via [fastify-cli](https://github.com/fastify/fastify-cli)
, a separate tool for scaffolding and managing Fastify projects.
First, install `fastify-cli`:
npm i fastify-cli
You can also install it globally with `-g`.
Then, add the following lines to `package.json`:
{ "scripts": { "start": "fastify start server.js" }}
And create your server file(s):
// server.js'use strict'module.exports = async function (fastify, opts) { fastify.get('/', async (request, reply) => { return { hello: 'world' } })}
Then run your server with:
npm start
### Slides and Videos[](https://fastify.dev/docs/latest/Guides/Getting-Started/#slides-and-videos "Direct link to Slides and Videos")
* Slides
* [Take your HTTP server to ludicrous speed](https://mcollina.github.io/take-your-http-server-to-ludicrous-speed)
by [@mcollina](https://github.com/mcollina)
* [What if I told you that HTTP can be fast](https://delvedor.github.io/What-if-I-told-you-that-HTTP-can-be-fast)
by [@delvedor](https://github.com/delvedor)
* Videos
* [Take your HTTP server to ludicrous speed](https://www.youtube.com/watch?v=5z46jJZNe8k)
by [@mcollina](https://github.com/mcollina)
* [What if I told you that HTTP can be fast](https://www.webexpo.net/prague2017/talk/what-if-i-told-you-that-http-can-be-fast/)
by [@delvedor](https://github.com/delvedor)
* [Getting Started](https://fastify.dev/docs/latest/Guides/Getting-Started/#getting-started)
* [Install](https://fastify.dev/docs/latest/Guides/Getting-Started/#install)
* [Your first server](https://fastify.dev/docs/latest/Guides/Getting-Started/#your-first-server)
* [Your first plugin](https://fastify.dev/docs/latest/Guides/Getting-Started/#your-first-plugin)
* [Loading order of your plugins](https://fastify.dev/docs/latest/Guides/Getting-Started/#loading-order-of-your-plugins)
* [Validate your data](https://fastify.dev/docs/latest/Guides/Getting-Started/#validate-your-data)
* [Serialize your data](https://fastify.dev/docs/latest/Guides/Getting-Started/#serialize-your-data)
* [Parsing request payloads](https://fastify.dev/docs/latest/Guides/Getting-Started/#parsing-request-payloads)
* [Extend your server](https://fastify.dev/docs/latest/Guides/Getting-Started/#extend-your-server)
* [Test your server](https://fastify.dev/docs/latest/Guides/Getting-Started/#test-your-server)
* [Run your server from CLI](https://fastify.dev/docs/latest/Guides/Getting-Started/#run-your-server-from-cli)
* [Slides and Videos](https://fastify.dev/docs/latest/Guides/Getting-Started/#slides-and-videos)
---
# Index | Fastify
[Skip to main content](https://fastify.dev/docs/latest/Reference/#__docusaurus_skipToContent_fallback)
Version: latest (v5.4.x)
On this page
Core Documents[](https://fastify.dev/docs/latest/Reference/#core-documents "Direct link to Core Documents")
-------------------------------------------------------------------------------------------------------------
For the full table of contents (TOC), see [below](https://fastify.dev/docs/latest/Reference/#reference-toc)
. The following list is a subset of the full TOC that detail core Fastify APIs and concepts in order of most likely importance to the reader:
* [Server](https://fastify.dev/docs/latest/Reference/Server/)
: Documents the core Fastify API. Includes documentation for the factory function and the object returned by the factory function.
* [Lifecycle](https://fastify.dev/docs/latest/Reference/Lifecycle/)
: Explains the Fastify request lifecycle and illustrates where [Hooks](https://fastify.dev/docs/latest/Reference/Hooks/)
are available for integrating with it.
* [Routes](https://fastify.dev/docs/latest/Reference/Routes/)
: Details how to register routes with Fastify and how Fastify builds and evaluates the routing trie.
* [Request](https://fastify.dev/docs/latest/Reference/Request/)
: Details Fastify's request object that is passed into each request handler.
* [Reply](https://fastify.dev/docs/latest/Reference/Reply/)
: Details Fastify's response object available to each request handler.
* [Validation and Serialization](https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/)
: Details Fastify's support for validating incoming data and how Fastify serializes data for responses.
* [Plugins](https://fastify.dev/docs/latest/Reference/Plugins/)
: Explains Fastify's plugin architecture and API.
* [Encapsulation](https://fastify.dev/docs/latest/Reference/Encapsulation/)
: Explains a core concept upon which all Fastify plugins are built.
* [Decorators](https://fastify.dev/docs/latest/Reference/Decorators/)
: Explains the server, request, and response decorator APIs.
* [Hooks](https://fastify.dev/docs/latest/Reference/Hooks/)
: Details the API by which Fastify plugins can inject themselves into Fastify's handling of the request lifecycle.
Reference Documentation Table Of Contents[](https://fastify.dev/docs/latest/Reference/#reference-documentation-table-of-contents "Direct link to Reference Documentation Table Of Contents")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
This table of contents is in alphabetical order.
* [Content Type Parser](https://fastify.dev/docs/latest/Reference/ContentTypeParser/)
: Documents Fastify's default content type parser and how to add support for new content types.
* [Decorators](https://fastify.dev/docs/latest/Reference/Decorators/)
: Explains the server, request, and response decorator APIs.
* [Encapsulation](https://fastify.dev/docs/latest/Reference/Encapsulation/)
: Explains a core concept upon which all Fastify plugins are built.
* [Errors](https://fastify.dev/docs/latest/Reference/Errors/)
: Details how Fastify handles errors and lists the standard set of errors Fastify generates.
* [Hooks](https://fastify.dev/docs/latest/Reference/Hooks/)
: Details the API by which Fastify plugins can inject themselves into Fastify's handling of the request lifecycle.
* [HTTP2](https://fastify.dev/docs/latest/Reference/HTTP2/)
: Details Fastify's HTTP2 support.
* [Lifecycle](https://fastify.dev/docs/latest/Reference/Lifecycle/)
: Explains the Fastify request lifecycle and illustrates where [Hooks](https://fastify.dev/docs/latest/Reference/Hooks/)
are available for integrating with it.
* [Logging](https://fastify.dev/docs/latest/Reference/Logging/)
: Details Fastify's included logging and how to customize it.
* [Long Term Support](https://fastify.dev/docs/latest/Reference/LTS/)
: Explains Fastify's long term support (LTS) guarantee and the exceptions possible to the [semver](https://semver.org/)
contract.
* [Middleware](https://fastify.dev/docs/latest/Reference/Middleware/)
: Details Fastify's support for Express.js style middleware.
* [Plugins](https://fastify.dev/docs/latest/Reference/Plugins/)
: Explains Fastify's plugin architecture and API.
* [Reply](https://fastify.dev/docs/latest/Reference/Reply/)
: Details Fastify's response object available to each request handler.
* [Request](https://fastify.dev/docs/latest/Reference/Request/)
: Details Fastify's request object that is passed into each request handler.
* [Routes](https://fastify.dev/docs/latest/Reference/Routes/)
: Details how to register routes with Fastify and how Fastify builds and evaluates the routing trie.
* [Server](https://fastify.dev/docs/latest/Reference/Server/)
: Documents the core Fastify API. Includes documentation for the factory function and the object returned by the factory function.
* [TypeScript](https://fastify.dev/docs/latest/Reference/TypeScript/)
: Documents Fastify's TypeScript support and provides recommendations for writing applications in TypeScript that utilize Fastify.
* [Validation and Serialization](https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/)
: Details Fastify's support for validating incoming data and how Fastify serializes data for responses.
* [Warnings](https://fastify.dev/docs/latest/Reference/Warnings/)
: Details the warnings Fastify emits and how to solve them.
* [Core Documents](https://fastify.dev/docs/latest/Reference/#core-documents)
* [Reference Documentation Table Of Contents](https://fastify.dev/docs/latest/Reference/#reference-documentation-table-of-contents)
---
# Index | Fastify
[Skip to main content](https://fastify.dev/docs/latest/Guides/#__docusaurus_skipToContent_fallback)
Version: latest (v5.4.x)
On this page
Guides Table Of Contents[](https://fastify.dev/docs/latest/Guides/#guides-table-of-contents "Direct link to Guides Table Of Contents")
----------------------------------------------------------------------------------------------------------------------------------------
This table of contents is in alphabetical order.
* [Benchmarking](https://fastify.dev/docs/latest/Guides/Benchmarking/)
: This guide introduces how to benchmark applications based on Fastify.
* [Contributing](https://fastify.dev/docs/latest/Guides/Contributing/)
: Details how to participate in the development of Fastify, and shows how to setup an environment compatible with the project's code style.
* [Delay Accepting Requests](https://fastify.dev/docs/latest/Guides/Delay-Accepting-Requests/)
: A practical guide on how to delay serving requests to specific routes until some condition is met in your application. This guide focuses on solving the problem using [`Hooks`](https://fastify.dev/docs/latest/Reference/Hooks/)
, [`Decorators`](https://fastify.dev/docs/latest/Reference/Decorators/)
, and [`Plugins`](https://fastify.dev/docs/latest/Reference/Plugins/)
.
* [Detecting When Clients Abort](https://fastify.dev/docs/latest/Guides/Detecting-When-Clients-Abort/)
: A practical guide on detecting if and when a client aborts a request.
* [Ecosystem](https://fastify.dev/docs/latest/Guides/Ecosystem/)
: Lists all core plugins and many known community plugins.
* [Fluent Schema](https://fastify.dev/docs/latest/Guides/Fluent-Schema/)
: Shows how JSON Schema can be written with a fluent API and used in Fastify.
* [Getting Started](https://fastify.dev/docs/latest/Guides/Getting-Started/)
: Introduction tutorial for Fastify. This is where beginners should start.
* [Migration Guide (v4)](https://fastify.dev/docs/latest/Guides/Migration-Guide-V4/)
: Details how to migrate to Fastify v4 from earlier versions.
* [Migration Guide (v3)](https://fastify.dev/docs/latest/Guides/Migration-Guide-V3/)
: Details how to migrate to Fastify v3 from earlier versions.
* [Plugins Guide](https://fastify.dev/docs/latest/Guides/Plugins-Guide/)
: An informal introduction to writing Fastify plugins.
* [Prototype Poisoning](https://fastify.dev/docs/latest/Guides/Prototype-Poisoning/)
: A description of how the prototype poisoning attack works and is mitigated.
* [Recommendations](https://fastify.dev/docs/latest/Guides/Recommendations/)
: Recommendations for how to deploy Fastify into production environments.
* [Serverless](https://fastify.dev/docs/latest/Guides/Serverless/)
: Details on how to deploy Fastify applications in various Function as a Service (FaaS) environments.
* [Style Guide](https://fastify.dev/docs/latest/Guides/Style-Guide/)
: Explains the writing style we use for the Fastify documentation for those who want to contribute documentation.
* [Testing](https://fastify.dev/docs/latest/Guides/Testing/)
: Explains how to write unit tests for Fastify applications.
* [Write Plugin](https://fastify.dev/docs/latest/Guides/Write-Plugin/)
: A set of guidelines for what the Fastify team considers good practices for writing a Fastify plugin.
* [Guides Table Of Contents](https://fastify.dev/docs/latest/Guides/#guides-table-of-contents)
---
# Benchmarking | Fastify
[Skip to main content](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#__docusaurus_skipToContent_fallback)
This is documentation for Fastify **v1.14.x**, which is no longer actively maintained.
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
For information about support options for end-of-life versions, see the [Long Term Support](https://fastify.dev/docs/latest/Reference/LTS)
page.
Version: v1.14.x
On this page
Benchmarking[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#benchmarking "Direct link to Benchmarking")
-------------------------------------------------------------------------------------------------------------------------
Benchmarking is important if you want to measure how a change can impact your application performance. We provide a simple way to benchmark your application from the point of view of a user and contributor. The setup allows you to automate benchmarks in different branches on different Node.js versions.
The modules we'll use:
* [Autocannon](https://github.com/mcollina/autocannon)
: A HTTP/1.1 benchmarking tool written in node.
* [Branch-comparer](https://github.com/StarpTech/branch-comparer)
: Checkout multiple git branches, execute scripts and log the results.
* [Concurrently](https://github.com/kimmobrunfeldt/concurrently)
: Run commands concurrently.
* [Npx](https://github.com/zkat/npx)
NPM package runner - We using it to run scripts against different Node.js Versions and execute local binaries. Shipped with npm@5.2.0.
Simple[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#simple "Direct link to Simple")
-------------------------------------------------------------------------------------------------------
### Run the test in the current branch[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-the-current-branch "Direct link to Run the test in the current branch")
npm run benchmark
### Run the test against different Node.js versions ✨[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-against-different-nodejs-versions- "Direct link to Run the test against different Node.js versions ✨")
npx -p node@6 -- npm run benchmark
Advanced[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#advanced "Direct link to Advanced")
-------------------------------------------------------------------------------------------------------------
### Run the test in different branches[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-different-branches "Direct link to Run the test in different branches")
branchcmp --rounds 2 --script "npm run benchmark"
### Run the test in different branches against different Node.js versions ✨[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-different-branches-against-different-nodejs-versions- "Direct link to Run the test in different branches against different Node.js versions ✨")
branchcmp --rounds 2 --script "npm run benchmark"
### Compare current branch with master (Gitflow)[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#compare-current-branch-with-master-gitflow "Direct link to Compare current branch with master (Gitflow)")
branchcmp --rounds 2 --gitflow --script "npm run benchmark"
or
npm run bench
### Run different examples[](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-different-examples "Direct link to Run different examples")
branchcmp --rounds 2 -s "node ./node_modules/concurrently -k -s first \"node ./examples/asyncawait.js\" \"node ./node_modules/autocannon -c 100 -d 5 -p 10 localhost:3000/\""
* [Benchmarking](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#benchmarking)
* [Simple](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#simple)
* [Run the test in the current branch](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-the-current-branch)
* [Run the test against different Node.js versions ✨](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-against-different-nodejs-versions-)
* [Advanced](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#advanced)
* [Run the test in different branches](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-different-branches)
* [Run the test in different branches against different Node.js versions ✨](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-the-test-in-different-branches-against-different-nodejs-versions-)
* [Compare current branch with master (Gitflow)](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#compare-current-branch-with-master-gitflow)
* [Run different examples](https://fastify.dev/docs/v1.14.x/Documentation/Benchmarking/#run-different-examples)
---
# Benchmarking | Fastify
[Skip to main content](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#__docusaurus_skipToContent_fallback)
This is documentation for Fastify **v2.15.x**, which is no longer actively maintained.
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/)
** (latest (v5.4.x)).
For information about support options for end-of-life versions, see the [Long Term Support](https://fastify.dev/docs/latest/Reference/LTS)
page.
Version: v2.15.x
On this page
Benchmarking[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#benchmarking "Direct link to Benchmarking")
-------------------------------------------------------------------------------------------------------------------------
Benchmarking is important if you want to measure how a change can impact the performance of your application. We provide a simple way to benchmark your application from the point of view of a user and contributor. The setup allows you to automate benchmarks in different branches and on different Node.js versions.
The modules we'll use:
* [Autocannon](https://github.com/mcollina/autocannon)
: A HTTP/1.1 benchmarking tool written in node.
* [Branch-comparer](https://github.com/StarpTech/branch-comparer)
: Checkout multiple git branches, execute scripts and log the results.
* [Concurrently](https://github.com/kimmobrunfeldt/concurrently)
: Run commands concurrently.
* [Npx](https://github.com/zkat/npx)
NPM package runner - We are using it to run scripts against different Node.js Versions and to execute local binaries. Shipped with npm@5.2.0.
Simple[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#simple "Direct link to Simple")
-------------------------------------------------------------------------------------------------------
### Run the test in the current branch[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-the-current-branch "Direct link to Run the test in the current branch")
npm run benchmark
### Run the test against different Node.js versions ✨[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-against-different-nodejs-versions- "Direct link to Run the test against different Node.js versions ✨")
npx -p node@6 -- npm run benchmark
Advanced[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#advanced "Direct link to Advanced")
-------------------------------------------------------------------------------------------------------------
### Run the test in different branches[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-different-branches "Direct link to Run the test in different branches")
branchcmp --rounds 2 --script "npm run benchmark"
### Run the test in different branches against different Node.js versions ✨[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-different-branches-against-different-nodejs-versions- "Direct link to Run the test in different branches against different Node.js versions ✨")
branchcmp --rounds 2 --script "npm run benchmark"
### Compare current branch with master (Gitflow)[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#compare-current-branch-with-master-gitflow "Direct link to Compare current branch with master (Gitflow)")
branchcmp --rounds 2 --gitflow --script "npm run benchmark"
or
npm run bench
### Run different examples[](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-different-examples "Direct link to Run different examples")
branchcmp --rounds 2 -s "node ./node_modules/concurrently -k -s first \"node ./examples/asyncawait.js\" \"node ./node_modules/autocannon -c 100 -d 5 -p 10 localhost:3000/\""
* [Benchmarking](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#benchmarking)
* [Simple](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#simple)
* [Run the test in the current branch](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-the-current-branch)
* [Run the test against different Node.js versions ✨](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-against-different-nodejs-versions-)
* [Advanced](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#advanced)
* [Run the test in different branches](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-different-branches)
* [Run the test in different branches against different Node.js versions ✨](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-the-test-in-different-branches-against-different-nodejs-versions-)
* [Compare current branch with master (Gitflow)](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#compare-current-branch-with-master-gitflow)
* [Run different examples](https://fastify.dev/docs/v2.15.x/Documentation/Benchmarking/#run-different-examples)
---
# LTS | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/LTS/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Long Term Support[](https://fastify.dev/docs/v5.4.x/Reference/LTS/#long-term-support "Direct link to Long Term Support")
--------------------------------------------------------------------------------------------------------------------------
Fastify's Long Term Support (LTS) is provided according to the schedule laid out in this document:
1. Major releases, "X" release of [semantic versioning](https://semver.org/)
X.Y.Z release versions, are supported for a minimum period of six months from their release date. The release date of any specific version can be found at [https://github.com/fastify/fastify/releases](https://github.com/fastify/fastify/releases)
.
2. Major releases will receive security updates for an additional six months from the release of the next major release. After this period we will still review and release security fixes as long as they are provided by the community and they do not violate other constraints, e.g. minimum supported Node.js version.
3. Major releases will be tested and verified against all Node.js release lines that are supported by the [Node.js LTS policy](https://github.com/nodejs/Release)
within the LTS period of that given Fastify release line. This implies that only the latest Node.js release of a given line is supported.
4. In addition to Node.js runtime, major releases of Fastify will also be tested and verified against alternative runtimes that are compatible with Node.js. The maintenance teams of these alternative runtimes are responsible for ensuring and guaranteeing these tests work properly.
1. [N|Solid](https://docs.nodesource.com/docs/product_suite)
tests and verifies each Fastify major release against current N|Solid LTS versions. NodeSource ensures Fastify compatibility with N|Solid, aligning with the support scope of N|Solid LTS versions at the time of the Fastify release. This guarantees N|Solid users can confidently use Fastify.
A "month" is defined as 30 consecutive days.
> Security Releases and Semver[](https://fastify.dev/docs/v5.4.x/Reference/LTS/#security-releases-and-semver "Direct link to Security Releases and Semver")
>
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
> As a consequence of providing long-term support for major releases, there are occasions where we need to release breaking changes as a _minor_ version release. Such changes will _always_ be noted in the [release notes](https://github.com/fastify/fastify/releases)
> .
>
> To avoid automatically receiving breaking security updates it is possible to use the tilde (`~`) range qualifier. For example, to get patches for the 3.15 release, and avoid automatically updating to the 3.16 release, specify the dependency as `"fastify": "~3.15.x"`. This will leave your application vulnerable, so please use it with caution.
### Security Support Beyond LTS[](https://fastify.dev/docs/v5.4.x/Reference/LTS/#security-support-beyond-lts "Direct link to Security Support Beyond LTS")
Fastify's partner, HeroDevs, provides commercial security support through the OpenJS Ecosystem Sustainability Program for versions of Fastify that are EOL. For more information, see their [Never Ending Support](https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=eol_support_fastify)
service.
### Schedule[](https://fastify.dev/docs/v5.4.x/Reference/LTS/#schedule "Direct link to Schedule")
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
### CI tested operating systems[](https://fastify.dev/docs/v5.4.x/Reference/LTS/#ci-tested-operating-systems "Direct link to CI tested operating systems")
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)
for further details on what the latest virtual environment is in relation to the YAML workflow labels below:
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
| Windows | `windows-latest` | npm | 20 | v5(20) |
| MacOS | `macos-latest` | npm | 20 | v5(20) |
Using [yarn](https://yarnpkg.com/)
might require passing the `--ignore-engines` flag.
* [Long Term Support](https://fastify.dev/docs/v5.4.x/Reference/LTS/#long-term-support)
* [Security Releases and Semver](https://fastify.dev/docs/v5.4.x/Reference/LTS/#security-releases-and-semver)
* [Security Support Beyond LTS](https://fastify.dev/docs/v5.4.x/Reference/LTS/#security-support-beyond-lts)
* [Schedule](https://fastify.dev/docs/v5.4.x/Reference/LTS/#schedule)
* [CI tested operating systems](https://fastify.dev/docs/v5.4.x/Reference/LTS/#ci-tested-operating-systems)
---
# LTS | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/LTS/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/LTS/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Long Term Support[](https://fastify.dev/docs/v5.3.x/Reference/LTS/#long-term-support "Direct link to Long Term Support")
--------------------------------------------------------------------------------------------------------------------------
Fastify's Long Term Support (LTS) is provided according to the schedule laid out in this document:
1. Major releases, "X" release of [semantic versioning](https://semver.org/)
X.Y.Z release versions, are supported for a minimum period of six months from their release date. The release date of any specific version can be found at [https://github.com/fastify/fastify/releases](https://github.com/fastify/fastify/releases)
.
2. Major releases will receive security updates for an additional six months from the release of the next major release. After this period we will still review and release security fixes as long as they are provided by the community and they do not violate other constraints, e.g. minimum supported Node.js version.
3. Major releases will be tested and verified against all Node.js release lines that are supported by the [Node.js LTS policy](https://github.com/nodejs/Release)
within the LTS period of that given Fastify release line. This implies that only the latest Node.js release of a given line is supported.
4. In addition to Node.js runtime, major releases of Fastify will also be tested and verified against alternative runtimes that are compatible with Node.js. The maintenance teams of these alternative runtimes are responsible for ensuring and guaranteeing these tests work properly.
1. [N|Solid](https://docs.nodesource.com/docs/product_suite)
tests and verifies each Fastify major release against current N|Solid LTS versions. NodeSource ensures Fastify compatibility with N|Solid, aligning with the support scope of N|Solid LTS versions at the time of the Fastify release. This guarantees N|Solid users can confidently use Fastify.
A "month" is defined as 30 consecutive days.
> Security Releases and Semver[](https://fastify.dev/docs/v5.3.x/Reference/LTS/#security-releases-and-semver "Direct link to Security Releases and Semver")
>
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
> As a consequence of providing long-term support for major releases, there are occasions where we need to release breaking changes as a _minor_ version release. Such changes will _always_ be noted in the [release notes](https://github.com/fastify/fastify/releases)
> .
>
> To avoid automatically receiving breaking security updates it is possible to use the tilde (`~`) range qualifier. For example, to get patches for the 3.15 release, and avoid automatically updating to the 3.16 release, specify the dependency as `"fastify": "~3.15.x"`. This will leave your application vulnerable, so please use it with caution.
### Security Support Beyond LTS[](https://fastify.dev/docs/v5.3.x/Reference/LTS/#security-support-beyond-lts "Direct link to Security Support Beyond LTS")
Fastify's partner, HeroDevs, provides commercial security support through the OpenJS Ecosystem Sustainability Program for versions of Fastify that are EOL. For more information, see their [Never Ending Support](https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=eol_support_fastify)
service.
### Schedule[](https://fastify.dev/docs/v5.3.x/Reference/LTS/#schedule "Direct link to Schedule")
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
### CI tested operating systems[](https://fastify.dev/docs/v5.3.x/Reference/LTS/#ci-tested-operating-systems "Direct link to CI tested operating systems")
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)
for further details on what the latest virtual environment is in relation to the YAML workflow labels below:
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
| Windows | `windows-latest` | npm | 20 | v5(20) |
| MacOS | `macos-latest` | npm | 20 | v5(20) |
Using [yarn](https://yarnpkg.com/)
might require passing the `--ignore-engines` flag.
* [Long Term Support](https://fastify.dev/docs/v5.3.x/Reference/LTS/#long-term-support)
* [Security Releases and Semver](https://fastify.dev/docs/v5.3.x/Reference/LTS/#security-releases-and-semver)
* [Security Support Beyond LTS](https://fastify.dev/docs/v5.3.x/Reference/LTS/#security-support-beyond-lts)
* [Schedule](https://fastify.dev/docs/v5.3.x/Reference/LTS/#schedule)
* [CI tested operating systems](https://fastify.dev/docs/v5.3.x/Reference/LTS/#ci-tested-operating-systems)
---
# LTS | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/LTS/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/LTS/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Long Term Support[](https://fastify.dev/docs/v5.2.x/Reference/LTS/#long-term-support "Direct link to Long Term Support")
--------------------------------------------------------------------------------------------------------------------------
Fastify's Long Term Support (LTS) is provided according to the schedule laid out in this document:
1. Major releases, "X" release of [semantic versioning](https://semver.org/)
X.Y.Z release versions, are supported for a minimum period of six months from their release date. The release date of any specific version can be found at [https://github.com/fastify/fastify/releases](https://github.com/fastify/fastify/releases)
.
2. Major releases will receive security updates for an additional six months from the release of the next major release. After this period we will still review and release security fixes as long as they are provided by the community and they do not violate other constraints, e.g. minimum supported Node.js version.
3. Major releases will be tested and verified against all Node.js release lines that are supported by the [Node.js LTS policy](https://github.com/nodejs/Release)
within the LTS period of that given Fastify release line. This implies that only the latest Node.js release of a given line is supported.
4. In addition to Node.js runtime, major releases of Fastify will also be tested and verified against alternative runtimes that are compatible with Node.js. The maintenance teams of these alternative runtimes are responsible for ensuring and guaranteeing these tests work properly.
1. [N|Solid](https://docs.nodesource.com/docs/product_suite)
tests and verifies each Fastify major release against current N|Solid LTS versions. NodeSource ensures Fastify compatibility with N|Solid, aligning with the support scope of N|Solid LTS versions at the time of the Fastify release. This guarantees N|Solid users can confidently use Fastify.
A "month" is defined as 30 consecutive days.
> Security Releases and Semver[](https://fastify.dev/docs/v5.2.x/Reference/LTS/#security-releases-and-semver "Direct link to Security Releases and Semver")
>
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
> As a consequence of providing long-term support for major releases, there are occasions where we need to release breaking changes as a _minor_ version release. Such changes will _always_ be noted in the [release notes](https://github.com/fastify/fastify/releases)
> .
>
> To avoid automatically receiving breaking security updates it is possible to use the tilde (`~`) range qualifier. For example, to get patches for the 3.15 release, and avoid automatically updating to the 3.16 release, specify the dependency as `"fastify": "~3.15.x"`. This will leave your application vulnerable, so please use it with caution.
### Security Support Beyond LTS[](https://fastify.dev/docs/v5.2.x/Reference/LTS/#security-support-beyond-lts "Direct link to Security Support Beyond LTS")
Fastify's partner, HeroDevs, provides commercial security support through the OpenJS Ecosystem Sustainability Program for versions of Fastify that are EOL. For more information, see their [Never Ending Support](https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=eol_support_fastify)
service.
### Schedule[](https://fastify.dev/docs/v5.2.x/Reference/LTS/#schedule "Direct link to Schedule")
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
### CI tested operating systems[](https://fastify.dev/docs/v5.2.x/Reference/LTS/#ci-tested-operating-systems "Direct link to CI tested operating systems")
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)
for further details on what the latest virtual environment is in relation to the YAML workflow labels below:
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
| Windows | `windows-latest` | npm | 20 | v5(20) |
| MacOS | `macos-latest` | npm | 20 | v5(20) |
Using [yarn](https://yarnpkg.com/)
might require passing the `--ignore-engines` flag.
* [Long Term Support](https://fastify.dev/docs/v5.2.x/Reference/LTS/#long-term-support)
* [Security Releases and Semver](https://fastify.dev/docs/v5.2.x/Reference/LTS/#security-releases-and-semver)
* [Security Support Beyond LTS](https://fastify.dev/docs/v5.2.x/Reference/LTS/#security-support-beyond-lts)
* [Schedule](https://fastify.dev/docs/v5.2.x/Reference/LTS/#schedule)
* [CI tested operating systems](https://fastify.dev/docs/v5.2.x/Reference/LTS/#ci-tested-operating-systems)
---
# LTS | Fastify
[Skip to main content](https://fastify.dev/docs/v5.1.x/Reference/LTS/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/LTS/)
** (latest (v5.4.x)).
Version: v5.1.x
On this page
Long Term Support[](https://fastify.dev/docs/v5.1.x/Reference/LTS/#long-term-support "Direct link to Long Term Support")
--------------------------------------------------------------------------------------------------------------------------
``
Fastify's Long Term Support (LTS) is provided according to the schedule laid out in this document:
1. Major releases, "X" release of [semantic versioning](https://semver.org/)
X.Y.Z release versions, are supported for a minimum period of six months from their release date. The release date of any specific version can be found at [https://github.com/fastify/fastify/releases](https://github.com/fastify/fastify/releases)
.
2. Major releases will receive security updates for an additional six months from the release of the next major release. After this period we will still review and release security fixes as long as they are provided by the community and they do not violate other constraints, e.g. minimum supported Node.js version.
3. Major releases will be tested and verified against all Node.js release lines that are supported by the [Node.js LTS policy](https://github.com/nodejs/Release)
within the LTS period of that given Fastify release line. This implies that only the latest Node.js release of a given line is supported.
4. In addition to Node.js runtime, major releases of Fastify will also be tested and verified against alternative runtimes that are compatible with Node.js. The maintenance teams of these alternative runtimes are responsible for ensuring and guaranteeing these tests work properly.
1. [N|Solid](https://docs.nodesource.com/nsolid)
, maintained by NodeSource, commits to testing and verifying each Fastify major release against the N|Solid LTS versions that are current at the time of the Fastify release. NodeSource guarantees that Fastify will be compatible and function correctly with N|Solid, aligning with the support and compatibility scope of the N|Solid LTS versions available at the time of the Fastify release. This ensures users of N|Solid can confidently use Fastify.
A "month" is defined as 30 consecutive days.
> Security Releases and Semver[](https://fastify.dev/docs/v5.1.x/Reference/LTS/#security-releases-and-semver "Direct link to Security Releases and Semver")
>
> -----------------------------------------------------------------------------------------------------------------------------------------------------------
>
> As a consequence of providing long-term support for major releases, there are occasions where we need to release breaking changes as a _minor_ version release. Such changes will _always_ be noted in the [release notes](https://github.com/fastify/fastify/releases)
> .
>
> To avoid automatically receiving breaking security updates it is possible to use the tilde (`~`) range qualifier. For example, to get patches for the 3.15 release, and avoid automatically updating to the 3.16 release, specify the dependency as `"fastify": "~3.15.x"`. This will leave your application vulnerable, so please use with caution.
### Schedule[](https://fastify.dev/docs/v5.1.x/Reference/LTS/#schedule "Direct link to Schedule")
``
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
### CI tested operating systems[](https://fastify.dev/docs/v5.1.x/Reference/LTS/#ci-tested-operating-systems "Direct link to CI tested operating systems")
``
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's documentation regarding workflow runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)
for further details on what the latest virtual environment is in relation to the YAML workflow labels below:
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
| --- | --- | --- | --- | --- |
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
| Windows | `windows-latest` | npm | 20 | v5(20) |
| MacOS | `macos-latest` | npm | 20 | v5(20) |
Using [yarn](https://yarnpkg.com/)
might require passing the `--ignore-engines` flag.
* [Long Term Support](https://fastify.dev/docs/v5.1.x/Reference/LTS/#long-term-support)
* [Security Releases and Semver](https://fastify.dev/docs/v5.1.x/Reference/LTS/#security-releases-and-semver)
* [Schedule](https://fastify.dev/docs/v5.1.x/Reference/LTS/#schedule)
* [CI tested operating systems](https://fastify.dev/docs/v5.1.x/Reference/LTS/#ci-tested-operating-systems)
---
# Lifecycle | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Lifecycle[](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#lifecycle "Direct link to Lifecycle")
--------------------------------------------------------------------------------------------------------
This schema shows the internal lifecycle of Fastify.
The right branch of each section shows the next phase of the lifecycle. The left branch shows the corresponding error code generated if the parent throws an error. All errors are automatically handled by Fastify.
Incoming Request │ └─▶ Routing │ └─▶ Instance Logger │ 4**/5** ◀─┴─▶ onRequest Hook │ 4**/5** ◀─┴─▶ preParsing Hook │ 4**/5** ◀─┴─▶ Parsing │ 4**/5** ◀─┴─▶ preValidation Hook │ 400 ◀─┴─▶ Validation │ 4**/5** ◀─┴─▶ preHandler Hook │ 4**/5** ◀─┴─▶ User Handler │ └─▶ Reply │ 4**/5** ◀─┴─▶ preSerialization Hook │ └─▶ onSend Hook │ 4**/5** ◀─┴─▶ Outgoing Response │ └─▶ onResponse Hook
Before or during the `User Handler`, `reply.hijack()` can be called to:
* Prevent Fastify from running subsequent hooks and the user handler
* Prevent Fastify from sending the response automatically
If `reply.raw` is used to send a response, `onResponse` hooks will still be executed.
Reply Lifecycle[](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#reply-lifecycle "Direct link to Reply Lifecycle")
--------------------------------------------------------------------------------------------------------------------------
When the user handles the request, the result may be:
* In an async handler: it returns a payload or throws an `Error`
* In a sync handler: it sends a payload or an `Error` instance
If the reply was hijacked, all subsequent steps are skipped. Otherwise, when submitted, the data flow is as follows:
★ schema validation Error │ └─▶ schemaErrorFormatter │ reply sent ◀── JSON ─┴─ Error instance │ │ ★ throw an Error ★ send or return │ │ │ │ │ │ ▼ │ reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler ◀─────┘ │ reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook │ └─▶ reply sent
`reply sent` means the JSON payload will be serialized by one of the following:
* The [reply serializer](https://fastify.dev/docs/v5.4.x/Reference/Server/#setreplyserializer)
if set
* The [serializer compiler](https://fastify.dev/docs/v5.4.x/Reference/Server/#setserializercompiler)
if a JSON schema is set for the HTTP status code
* The default `JSON.stringify` function
* [Lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#lifecycle)
* [Reply Lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#reply-lifecycle)
---
# HTTP2 | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
HTTP2[](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#http2 "Direct link to HTTP2")
----------------------------------------------------------------------------------------
_Fastify_ supports HTTP2 over HTTPS (h2) or plaintext (h2c).
Currently, none of the HTTP2-specific APIs are available through _Fastify_, but Node's `req` and `res` can be accessed through the `Request` and `Reply` interfaces. PRs are welcome.
### Secure (HTTPS)[](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#secure-https "Direct link to Secure (HTTPS)")
HTTP2 is supported in all modern browsers **only over a secure connection**:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
[ALPN negotiation](https://datatracker.ietf.org/doc/html/rfc7301)
allows support for both HTTPS and HTTP/2 over the same socket. Node core `req` and `res` objects can be either [HTTP/1](https://nodejs.org/api/http.html)
or [HTTP/2](https://nodejs.org/api/http2.html)
. _Fastify_ supports this out of the box:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { allowHTTP1: true, // fallback support for HTTP1 key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})// this route can be accessed through both protocolsfastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url https://localhost:3000
### Plain or insecure[](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#plain-or-insecure "Direct link to Plain or insecure")
For microservices, HTTP2 can connect in plain text, but this is not supported by browsers.
'use strict'const fastify = require('fastify')({ http2: true})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url http://localhost:3000
* [HTTP2](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#http2)
* [Secure (HTTPS)](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#secure-https)
* [Plain or insecure](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/#plain-or-insecure)
---
# Encapsulation | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Encapsulation[](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/#encapsulation "Direct link to Encapsulation")
------------------------------------------------------------------------------------------------------------------------
A fundamental feature of Fastify is the "encapsulation context." It governs which [decorators](https://fastify.dev/docs/v5.4.x/Reference/Decorators/)
, registered [hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/)
, and [plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
are available to [routes](https://fastify.dev/docs/v5.4.x/Reference/Routes/)
. A visual representation of the encapsulation context is shown in the following figure:

In the figure above, there are several entities:
1. The _root context_
2. Three _root plugins_
3. Two _child contexts_, each with:
* Two _child plugins_
* One _grandchild context_, each with:
* Three _child plugins_
Every _child context_ and _grandchild context_ has access to the _root plugins_. Within each _child context_, the _grandchild contexts_ have access to the _child plugins_ registered within the containing _child context_, but the containing _child context_ **does not** have access to the _child plugins_ registered within its _grandchild context_.
Given that everything in Fastify is a [plugin](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
except for the _root context_, every "context" and "plugin" in this example is a plugin that can consist of decorators, hooks, plugins, and routes. To put this example into concrete terms, consider a basic scenario of a REST API server with three routes: the first route (`/one`) requires authentication, the second route (`/two`) does not, and the third route (`/three`) has access to the same context as the second route. Using [@fastify/bearer-auth](https://github.com/fastify/fastify-bearer-auth)
to provide authentication, the code for this example is as follows:
'use strict'const fastify = require('fastify')()fastify.decorateRequest('answer', 42)fastify.register(async function authenticatedContext (childServer) { childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] }) childServer.route({ path: '/one', method: 'GET', handler (request, response) { response.send({ answer: request.answer, // request.foo will be undefined as it is only defined in publicContext foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } })})fastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } }) childServer.register(async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) })})fastify.listen({ port: 8000 })
The server example above demonstrates the encapsulation concepts from the original diagram:
1. Each _child context_ (`authenticatedContext`, `publicContext`, and `grandchildContext`) has access to the `answer` request decorator defined in the _root context_.
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth` plugin.
3. Both the `publicContext` and `grandchildContext` have access to the `foo` request decorator.
4. Only the `grandchildContext` has access to the `bar` request decorator.
To see this, start the server and issue requests:
# curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one{"answer":42}# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
Sharing Between Contexts[](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/#sharing-between-contexts "Direct link to Sharing Between Contexts")
---------------------------------------------------------------------------------------------------------------------------------------------------------
Each context in the prior example inherits _only_ from its parent contexts. Parent contexts cannot access entities within their descendant contexts. If needed, encapsulation can be broken using [fastify-plugin](https://github.com/fastify/fastify-plugin)
, making anything registered in a descendant context available to the parent context.
To allow `publicContext` access to the `bar` decorator in `grandchildContext`, rewrite the code as follows:
'use strict'const fastify = require('fastify')()const fastifyPlugin = require('fastify-plugin')fastify.decorateRequest('answer', 42)// `authenticatedContext` omitted for clarityfastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) childServer.register(fastifyPlugin(grandchildContext)) async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) }})fastify.listen({ port: 8000 })
Restarting the server and re-issuing the requests for `/two` and `/three`:
# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo","bar":"bar"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
* [Encapsulation](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/#encapsulation)
* [Sharing Between Contexts](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/#sharing-between-contexts)
---
# HTTP2 | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/HTTP2/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
HTTP2[](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#http2 "Direct link to HTTP2")
----------------------------------------------------------------------------------------
_Fastify_ supports HTTP2 over HTTPS (h2) or plaintext (h2c).
Currently, none of the HTTP2-specific APIs are available through _Fastify_, but Node's `req` and `res` can be accessed through the `Request` and `Reply` interfaces. PRs are welcome.
### Secure (HTTPS)[](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#secure-https "Direct link to Secure (HTTPS)")
HTTP2 is supported in all modern browsers **only over a secure connection**:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
[ALPN negotiation](https://datatracker.ietf.org/doc/html/rfc7301)
allows support for both HTTPS and HTTP/2 over the same socket. Node core `req` and `res` objects can be either [HTTP/1](https://nodejs.org/api/http.html)
or [HTTP/2](https://nodejs.org/api/http2.html)
. _Fastify_ supports this out of the box:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { allowHTTP1: true, // fallback support for HTTP1 key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})// this route can be accessed through both protocolsfastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url https://localhost:3000
### Plain or insecure[](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#plain-or-insecure "Direct link to Plain or insecure")
For microservices, HTTP2 can connect in plain text, but this is not supported by browsers.
'use strict'const fastify = require('fastify')({ http2: true})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url http://localhost:3000
* [HTTP2](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#http2)
* [Secure (HTTPS)](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#secure-https)
* [Plain or insecure](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/#plain-or-insecure)
---
# Middleware | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Middleware[](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#middleware "Direct link to Middleware")
------------------------------------------------------------------------------------------------------------
Starting with Fastify v3.0.0, middleware is not supported out of the box and requires an external plugin such as [`@fastify/express`](https://github.com/fastify/fastify-express)
or [`@fastify/middie`](https://github.com/fastify/middie)
.
An example of registering the [`@fastify/express`](https://github.com/fastify/fastify-express)
plugin to `use` Express middleware:
await fastify.register(require('@fastify/express'))fastify.use(require('cors')())fastify.use(require('dns-prefetch-control')())fastify.use(require('frameguard')())fastify.use(require('hsts')())fastify.use(require('ienoopen')())fastify.use(require('x-xss-protection')())
[`@fastify/middie`](https://github.com/fastify/middie)
can also be used, which provides support for simple Express-style middleware with improved performance:
await fastify.register(require('@fastify/middie'))fastify.use(require('cors')())
Middleware can be encapsulated, allowing control over where it runs using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.4.x/Guides/Plugins-Guide/)
.
Fastify middleware does not expose the `send` method or other methods specific to the Fastify [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply)
instance. This is because Fastify wraps the incoming `req` and `res` Node instances using the [Request](https://fastify.dev/docs/v5.4.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply)
objects internally, but this is done after the middleware phase. To create middleware, use the Node `req` and `res` instances. Alternatively, use the `preHandler` hook that already has the Fastify [Request](https://fastify.dev/docs/v5.4.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply)
instances. For more information, see [Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#hooks)
.
#### Restrict middleware execution to certain paths[](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#restrict-middleware-execution-to-certain-paths "Direct link to Restrict middleware execution to certain paths")
To run middleware under certain paths, pass the path as the first parameter to `use`.
> ℹ️ Note: This does not support routes with parameters (e.g. `/user/:id/comments`) and wildcards are not supported in multiple paths.
const path = require('node:path')const serveStatic = require('serve-static')// Single pathfastify.use('/css', serveStatic(path.join(__dirname, '/assets')))// Wildcard pathfastify.use('/css/(.*)', serveStatic(path.join(__dirname, '/assets')))// Multiple pathsfastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
### Alternatives[](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#alternatives "Direct link to Alternatives")
Fastify offers alternatives to commonly used middleware, such as [`@fastify/helmet`](https://github.com/fastify/fastify-helmet)
for [`helmet`](https://github.com/helmetjs/helmet)
, [`@fastify/cors`](https://github.com/fastify/fastify-cors)
for [`cors`](https://github.com/expressjs/cors)
, and [`@fastify/static`](https://github.com/fastify/fastify-static)
for [`serve-static`](https://github.com/expressjs/serve-static)
.
* [Middleware](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#middleware)
* [Alternatives](https://fastify.dev/docs/v5.4.x/Reference/Middleware/#alternatives)
---
# Technical Principles | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Principles/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Every decision in the Fastify framework and its official plugins is guided by the following technical principles:
1. “Zero” overhead in production
2. “Good” developer experience
3. Works great for small & big projects alike
4. Easy to migrate to microservices (or even serverless) and back
5. Security & data validation
6. If something could be a plugin, it likely should be
7. Easily testable
8. Do not monkeypatch core
9. Semantic versioning & Long Term Support
10. Specification adherence
"Zero" Overhead in Production[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#zero-overhead-in-production "Direct link to "Zero" Overhead in Production")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to implement features with minimal overhead. This is achieved by using fast algorithms, data structures, and JavaScript-specific features.
Since JavaScript does not offer zero-overhead data structures, this principle can conflict with providing a great developer experience and additional features, as these usually incur some overhead.
"Good" Developer Experience[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#good-developer-experience "Direct link to "Good" Developer Experience")
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to provide the best developer experience at its performance point. It offers a great out-of-the-box experience that is flexible enough to adapt to various situations.
For example, binary addons are forbidden because most JavaScript developers do not have access to a compiler.
Works great for small and big projects alike[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#works-great-for-small-and-big-projects-alike "Direct link to Works great for small and big projects alike")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Most applications start small and become more complex over time. Fastify aims to grow with this complexity, providing advanced features to structure codebases.
Easy to migrate to microservices (or even serverless) and back[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back "Direct link to Easy to migrate to microservices (or even serverless) and back")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Route deployment should not matter. The framework should "just work".
Security and Data Validation[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#security-and-data-validation "Direct link to Security and Data Validation")
------------------------------------------------------------------------------------------------------------------------------------------------------------------
A web framework is the first point of contact with untrusted data and must act as the first line of defense for the system.
If something could be a plugin, it likely should[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should "Direct link to If something could be a plugin, it likely should")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Recognizing the infinite use cases for an HTTP framework, catering to all in a single module would make the codebase unmaintainable. Therefore, hooks and options are provided to customize the framework as needed.
Easily testable[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#easily-testable "Direct link to Easily testable")
---------------------------------------------------------------------------------------------------------------------------
Testing Fastify applications should be a first-class concern.
Do not monkeypatch core[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#do-not-monkeypatch-core "Direct link to Do not monkeypatch core")
---------------------------------------------------------------------------------------------------------------------------------------------------
Monkeypatching Node.js APIs or installing globals that alter the runtime makes building modular applications harder and limits Fastify's use cases. Other frameworks do this; Fastify does not.
Semantic Versioning and Long Term Support[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#semantic-versioning-and-long-term-support "Direct link to Semantic Versioning and Long Term Support")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
A clear [Long Term Support strategy is provided](https://fastify.dev/docs/v5.4.x/Reference/LTS/)
to inform developers when to upgrade.
Specification adherence[](https://fastify.dev/docs/v5.4.x/Reference/Principles/#specification-adherence "Direct link to Specification adherence")
---------------------------------------------------------------------------------------------------------------------------------------------------
In doubt, we chose the strict behavior as defined by the relevant Specifications.
* ["Zero" Overhead in Production](https://fastify.dev/docs/v5.4.x/Reference/Principles/#zero-overhead-in-production)
* ["Good" Developer Experience](https://fastify.dev/docs/v5.4.x/Reference/Principles/#good-developer-experience)
* [Works great for small and big projects alike](https://fastify.dev/docs/v5.4.x/Reference/Principles/#works-great-for-small-and-big-projects-alike)
* [Easy to migrate to microservices (or even serverless) and back](https://fastify.dev/docs/v5.4.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back)
* [Security and Data Validation](https://fastify.dev/docs/v5.4.x/Reference/Principles/#security-and-data-validation)
* [If something could be a plugin, it likely should](https://fastify.dev/docs/v5.4.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should)
* [Easily testable](https://fastify.dev/docs/v5.4.x/Reference/Principles/#easily-testable)
* [Do not monkeypatch core](https://fastify.dev/docs/v5.4.x/Reference/Principles/#do-not-monkeypatch-core)
* [Semantic Versioning and Long Term Support](https://fastify.dev/docs/v5.4.x/Reference/Principles/#semantic-versioning-and-long-term-support)
* [Specification adherence](https://fastify.dev/docs/v5.4.x/Reference/Principles/#specification-adherence)
---
# Encapsulation | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Encapsulation/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Encapsulation[](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/#encapsulation "Direct link to Encapsulation")
------------------------------------------------------------------------------------------------------------------------
A fundamental feature of Fastify is the "encapsulation context." It governs which [decorators](https://fastify.dev/docs/v5.3.x/Reference/Decorators/)
, registered [hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/)
, and [plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
are available to [routes](https://fastify.dev/docs/v5.3.x/Reference/Routes/)
. A visual representation of the encapsulation context is shown in the following figure:

In the figure above, there are several entities:
1. The _root context_
2. Three _root plugins_
3. Two _child contexts_, each with:
* Two _child plugins_
* One _grandchild context_, each with:
* Three _child plugins_
Every _child context_ and _grandchild context_ has access to the _root plugins_. Within each _child context_, the _grandchild contexts_ have access to the _child plugins_ registered within the containing _child context_, but the containing _child context_ **does not** have access to the _child plugins_ registered within its _grandchild context_.
Given that everything in Fastify is a [plugin](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
except for the _root context_, every "context" and "plugin" in this example is a plugin that can consist of decorators, hooks, plugins, and routes. To put this example into concrete terms, consider a basic scenario of a REST API server with three routes: the first route (`/one`) requires authentication, the second route (`/two`) does not, and the third route (`/three`) has access to the same context as the second route. Using [@fastify/bearer-auth](https://github.com/fastify/fastify-bearer-auth)
to provide authentication, the code for this example is as follows:
'use strict'const fastify = require('fastify')()fastify.decorateRequest('answer', 42)fastify.register(async function authenticatedContext (childServer) { childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] }) childServer.route({ path: '/one', method: 'GET', handler (request, response) { response.send({ answer: request.answer, // request.foo will be undefined as it is only defined in publicContext foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } })})fastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } }) childServer.register(async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) })})fastify.listen({ port: 8000 })
The server example above demonstrates the encapsulation concepts from the original diagram:
1. Each _child context_ (`authenticatedContext`, `publicContext`, and `grandchildContext`) has access to the `answer` request decorator defined in the _root context_.
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth` plugin.
3. Both the `publicContext` and `grandchildContext` have access to the `foo` request decorator.
4. Only the `grandchildContext` has access to the `bar` request decorator.
To see this, start the server and issue requests:
# curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one{"answer":42}# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
Sharing Between Contexts[](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/#sharing-between-contexts "Direct link to Sharing Between Contexts")
---------------------------------------------------------------------------------------------------------------------------------------------------------
Each context in the prior example inherits _only_ from its parent contexts. Parent contexts cannot access entities within their descendant contexts. If needed, encapsulation can be broken using [fastify-plugin](https://github.com/fastify/fastify-plugin)
, making anything registered in a descendant context available to the parent context.
To allow `publicContext` access to the `bar` decorator in `grandchildContext`, rewrite the code as follows:
'use strict'const fastify = require('fastify')()const fastifyPlugin = require('fastify-plugin')fastify.decorateRequest('answer', 42)// `authenticatedContext` omitted for clarityfastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) childServer.register(fastifyPlugin(grandchildContext)) async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) }})fastify.listen({ port: 8000 })
Restarting the server and re-issuing the requests for `/two` and `/three`:
# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo","bar":"bar"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
* [Encapsulation](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/#encapsulation)
* [Sharing Between Contexts](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/#sharing-between-contexts)
---
# Plugins | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Plugins[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#plugins "Direct link to Plugins")
------------------------------------------------------------------------------------------------
Fastify can be extended with plugins, which can be a set of routes, a server [decorator](https://fastify.dev/docs/v5.4.x/Reference/Decorators/)
, or other functionality. Use the `register` API to add one or more plugins.
By default, `register` creates a _new scope_, meaning changes to the Fastify instance (via `decorate`) will not affect the current context ancestors, only its descendants. This feature enables plugin _encapsulation_ and _inheritance_, creating a _directed acyclic graph_ (DAG) and avoiding cross-dependency issues.
The [Getting Started](https://fastify.dev/docs/v5.4.x/Guides/Getting-Started/#your-first-plugin)
guide includes an example of using this API:
fastify.register(plugin, [options])
### Plugin Options[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#plugin-options "Direct link to Plugin Options")
The optional `options` parameter for `fastify.register` supports a predefined set of options that Fastify itself will use, except when the plugin has been wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin)
. This options object will also be passed to the plugin upon invocation, regardless of whether or not the plugin has been wrapped. The currently supported list of Fastify specific options is:
* [`logLevel`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-level)
* [`logSerializers`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-serializer)
* [`prefix`](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#route-prefixing-option)
These options will be ignored when used with fastify-plugin.
To avoid collisions, a plugin should consider namespacing its options. For example, a plugin `foo` might be registered like so:
fastify.register(require('fastify-foo'), { prefix: '/foo', foo: { fooOption1: 'value', fooOption2: 'value' }})
If collisions are not a concern, the plugin may accept the options object as-is:
fastify.register(require('fastify-foo'), { prefix: '/foo', fooOption1: 'value', fooOption2: 'value'})
The `options` parameter can also be a `Function` evaluated at plugin registration, providing access to the Fastify instance via the first argument:
const fp = require('fastify-plugin')fastify.register(fp((fastify, opts, done) => { fastify.decorate('foo_bar', { hello: 'world' }) done()}))// The opts argument of fastify-foo will be { hello: 'world' }fastify.register(require('fastify-foo'), parent => parent.foo_bar)
The Fastify instance passed to the function is the latest state of the **external Fastify instance** the plugin was declared on, allowing access to variables injected via [`decorate`](https://fastify.dev/docs/v5.4.x/Reference/Decorators/)
by preceding plugins according to the **order of registration**. This is useful if a plugin depends on changes made to the Fastify instance by a preceding plugin, such as utilizing an existing database connection.
Keep in mind that the Fastify instance passed to the function is the same as the one passed into the plugin, a copy of the external Fastify instance rather than a reference. Any usage of the instance will behave the same as it would if called within the plugin's function. For example, if `decorate` is called, the decorated variables will be available within the plugin's function unless it was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
.
#### Route Prefixing option[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#route-prefixing-option "Direct link to Route Prefixing option")
If an option with the key `prefix` and a `string` value is passed, Fastify will use it to prefix all the routes inside the register. For more info, check [here](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing)
.
Be aware that if routes are wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
, this option will not work (see the [workaround](https://fastify.dev/docs/v5.4.x/Reference/Routes/#fastify-plugin)
).
#### Error handling[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#error-handling "Direct link to Error handling")
Error handling is done by [avvio](https://github.com/mcollina/avvio#error-handling)
.
As a general rule, handle errors in the next `after` or `ready` block, otherwise they will be caught inside the `listen` callback.
fastify.register(require('my-plugin'))// `after` will be executed once// the previous declared `register` has finishedfastify.after(err => console.log(err))// `ready` will be executed once all the registers declared// have finished their executionfastify.ready(err => console.log(err))// `listen` is a special ready,// so it behaves in the same wayfastify.listen({ port: 3000 }, (err, address) => { if (err) console.log(err)})
### async/await[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#asyncawait "Direct link to async/await")
_async/await_ is supported by `after`, `ready`, and `listen`, as well as `fastify` being a Thenable.
await fastify.register(require('my-plugin'))await fastify.after()await fastify.ready()await fastify.listen({ port: 3000 })
Using `await` when registering a plugin loads the plugin and its dependencies, "finalizing" the encapsulation process. Any mutations to the plugin after it and its dependencies have been loaded will not be reflected in the parent instance.
#### ESM support[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#esm-support "Direct link to ESM support")
ESM is supported from [Node.js `v13.3.0`](https://nodejs.org/api/esm.html)
and above.
// main.mjsimport Fastify from 'fastify'const fastify = Fastify()fastify.register(import('./plugin.mjs'))fastify.listen({ port: 3000 }, console.log)// plugin.mjsasync function plugin (fastify, opts) { fastify.get('/', async (req, reply) => { return { hello: 'world' } })}export default plugin
### Create a plugin[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#create-a-plugin "Direct link to Create a plugin")
Creating a plugin is easy. Create a function that takes three parameters: the `fastify` instance, an `options` object, and the `done` callback.
Example:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) done()}
`register` can also be used inside another `register`:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) fastify.register(require('./other-plugin')) done()}
Remember, `register` always creates a new Fastify scope. If this is not needed, read the following section.
### Handle the scope[](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#handle-the-scope "Direct link to Handle the scope")
If `register` is used only to extend server functionality with [`decorate`](https://fastify.dev/docs/v5.4.x/Reference/Decorators/)
, tell Fastify not to create a new scope. Otherwise, changes will not be accessible in the upper scope.
There are two ways to avoid creating a new context:
* Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
module
* Use the `'skip-override'` hidden property
Using the `fastify-plugin` module is recommended, as it solves this problem and allows passing a version range of Fastify that the plugin will support:
const fp = require('fastify-plugin')module.exports = fp(function (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}, '0.x')
Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
documentation to learn more about how to use this module.
If not using `fastify-plugin`, the `'skip-override'` hidden property can be used, but it is not recommended. Future Fastify API changes will be your responsibility to update, whilst `fastify-plugin` ensures backward compatibility.
function yourPlugin (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}yourPlugin[Symbol.for('skip-override')] = truemodule.exports = yourPlugin
* [Plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#plugins)
* [Plugin Options](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#plugin-options)
* [async/await](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#asyncawait)
* [Create a plugin](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#create-a-plugin)
* [Handle the scope](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#handle-the-scope)
---
# ContentTypeParser | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
`Content-Type` Parser[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#content-type-parser "Direct link to content-type-parser")
------------------------------------------------------------------------------------------------------------------------------------------------
Fastify natively supports `'application/json'` and `'text/plain'` content types with a default charset of `utf-8`. These default parsers can be changed or removed.
Unsupported content types will throw an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error.
To support other content types, use the `addContentTypeParser` API or an existing [plugin](https://fastify.dev/ecosystem/)
.
As with other APIs, `addContentTypeParser` is encapsulated in the scope in which it is declared. If declared in the root scope, it is available everywhere; if declared in a plugin, it is available only in that scope and its children.
Fastify automatically adds the parsed request payload to the [Fastify request](https://fastify.dev/docs/v5.4.x/Reference/Request/)
object, accessible via `request.body`.
Note that for `GET` and `HEAD` requests, the payload is never parsed. For `OPTIONS` and `DELETE` requests, the payload is parsed only if a valid `content-type` header is provided. Unlike `POST`, `PUT`, and `PATCH`, the [catch-all](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#catch-all)
parser is not executed, and the payload is simply not parsed.
> ⚠ Warning: When using regular expressions to detect `Content-Type`, it is important to ensure proper detection. For example, to match `application/*`, use `/^application\/([\w-]+);?/` to match the [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#usage "Direct link to Usage")
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) })})// Handle multiple content types with the same functionfastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Async is also supported in Node versions >= 8.0.0fastify.addContentTypeParser('application/jsoff', async function (request, payload) { const res = await jsoffParserAsync(payload) return res})// Handle all content types that matches RegExpfastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) { imageParser(payload, function (err, body) { done(err, body) })})// Can use default JSON/Text parser for different content Typesfastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
Fastify first tries to match a content-type parser with a `string` value before trying to find a matching `RegExp`. For overlapping content types, it starts with the last one configured and ends with the first (last in, first out). To specify a general content type more precisely, first specify the general type, then the specific one, as shown below.
// Here only the second content type parser is called because its value also matches the first onefastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )// Here the desired behavior is achieved because fastify first tries to match the// `application/vnd.custom+xml` content type parserfastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
### Using addContentTypeParser with fastify.register[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister "Direct link to Using addContentTypeParser with fastify.register")
When using `addContentTypeParser` with `fastify.register`, avoid `await` when registering routes. Using `await` makes route registration asynchronous, potentially registering routes before `addContentTypeParser` is set.
#### Correct Usage[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#correct-usage "Direct link to Correct Usage")
const fastify = require('fastify')();fastify.register((fastify, opts) => { fastify.addContentTypeParser('application/json', function (request, payload, done) { jsonParser(payload, function (err, body) { done(err, body) }) }) fastify.get('/hello', async (req, res) => {});});
In addition to `addContentTypeParser`, the `hasContentTypeParser`, `removeContentTypeParser`, and `removeAllContentTypeParsers` APIs are available.
#### hasContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#hascontenttypeparser "Direct link to hasContentTypeParser")
Use the `hasContentTypeParser` API to check if a specific content type parser exists.
if (!fastify.hasContentTypeParser('application/jsoff')){ fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) }) })}
#### removeContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#removecontenttypeparser "Direct link to removeContentTypeParser")
`removeContentTypeParser` can remove a single content type or an array of content types, supporting both `string` and `RegExp`.
fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Removes the both built-in content type parsers so that only the content type parser for text/html is availablefastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
The `removeAllContentTypeParsers` API removes all existing content type parsers eliminating the need to specify each one individually. This API supports encapsulation and is useful for registering a [catch-all content type parser](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#catch-all)
that should be executed for every content type, ignoring built-in parsers.
fastify.removeAllContentTypeParsers()fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})
> ℹ️ Note: `function(req, done)` and `async function(req)` are still supported but deprecated.
#### Body Parser[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#body-parser "Direct link to Body Parser")
The request body can be parsed in two ways. First, add a custom content type parser and handle the request stream. Or second, use the `parseAs` option in the `addContentTypeParser` API, specifying `'string'` or `'buffer'`. Fastify will handle the stream, check the [maximum size](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-body-limit)
of the body, and the content length. If the limit is exceeded, the custom parser will not be invoked.
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) { try { const json = JSON.parse(body) done(null, json) } catch (err) { err.statusCode = 400 done(err, undefined) }})
See [`example/parser.js`](https://github.com/fastify/fastify/blob/main/examples/parser.js)
for an example.
##### Custom Parser Options[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#custom-parser-options "Direct link to Custom Parser Options")
* `parseAs` (string): `'string'` or `'buffer'` to designate how the incoming data should be collected. Default: `'buffer'`.
* `bodyLimit` (number): The maximum payload size, in bytes, that the custom parser will accept. Defaults to the global body limit passed to the [`Fastify factory function`](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit)
.
#### Catch-All[](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#catch-all "Direct link to Catch-All")
To catch all requests regardless of content type, use the `'*'` content type:
fastify.addContentTypeParser('*', function (request, payload, done) { let data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
All requests without a corresponding content type parser will be handled by this function.
This is also useful for piping the request stream. Define a content parser like:
fastify.addContentTypeParser('*', function (request, payload, done) { done()})
And then access the core HTTP request directly for piping:
app.post('/hello', (request, reply) => { reply.send(request.raw)})
Here is a complete example that logs incoming [json line](https://jsonlines.org/)
objects:
const split2 = require('split2')const pump = require('pump')fastify.addContentTypeParser('*', (request, payload, done) => { done(null, pump(payload, split2(JSON.parse)))})fastify.route({ method: 'POST', url: '/api/log/jsons', handler: (req, res) => { req.body.on('data', d => console.log(d)) // log every incoming object }})
For piping file uploads, check out [`@fastify/multipart`](https://github.com/fastify/fastify-multipart)
.
To execute the content type parser on all content types, call `removeAllContentTypeParsers` first.
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parserfastify.removeAllContentTypeParsers()fastify.addContentTypeParser('*', function (request, payload, done) { const data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
* [`Content-Type` Parser](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#content-type-parser)
* [Usage](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#usage)
* [Using addContentTypeParser with fastify.register](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister)
---
# ContentTypeParser | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/ContentTypeParser/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
`Content-Type` Parser[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#content-type-parser "Direct link to content-type-parser")
------------------------------------------------------------------------------------------------------------------------------------------------
Fastify natively supports `'application/json'` and `'text/plain'` content types with a default charset of `utf-8`. These default parsers can be changed or removed.
Unsupported content types will throw an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error.
To support other content types, use the `addContentTypeParser` API or an existing [plugin](https://fastify.dev/ecosystem/)
.
As with other APIs, `addContentTypeParser` is encapsulated in the scope in which it is declared. If declared in the root scope, it is available everywhere; if declared in a plugin, it is available only in that scope and its children.
Fastify automatically adds the parsed request payload to the [Fastify request](https://fastify.dev/docs/v5.3.x/Reference/Request/)
object, accessible via `request.body`.
Note that for `GET` and `HEAD` requests, the payload is never parsed. For `OPTIONS` and `DELETE` requests, the payload is parsed only if a valid `content-type` header is provided. Unlike `POST`, `PUT`, and `PATCH`, the [catch-all](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#catch-all)
parser is not executed, and the payload is simply not parsed.
> ⚠ Warning: When using regular expressions to detect `Content-Type`, it is important to ensure proper detection. For example, to match `application/*`, use `/^application\/([\w-]+);?/` to match the [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#usage "Direct link to Usage")
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) })})// Handle multiple content types with the same functionfastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Async is also supported in Node versions >= 8.0.0fastify.addContentTypeParser('application/jsoff', async function (request, payload) { const res = await jsoffParserAsync(payload) return res})// Handle all content types that matches RegExpfastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) { imageParser(payload, function (err, body) { done(err, body) })})// Can use default JSON/Text parser for different content Typesfastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
Fastify first tries to match a content-type parser with a `string` value before trying to find a matching `RegExp`. For overlapping content types, it starts with the last one configured and ends with the first (last in, first out). To specify a general content type more precisely, first specify the general type, then the specific one, as shown below.
// Here only the second content type parser is called because its value also matches the first onefastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )// Here the desired behavior is achieved because fastify first tries to match the// `application/vnd.custom+xml` content type parserfastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
### Using addContentTypeParser with fastify.register[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister "Direct link to Using addContentTypeParser with fastify.register")
When using `addContentTypeParser` with `fastify.register`, avoid `await` when registering routes. Using `await` makes route registration asynchronous, potentially registering routes before `addContentTypeParser` is set.
#### Correct Usage[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#correct-usage "Direct link to Correct Usage")
const fastify = require('fastify')();fastify.register((fastify, opts) => { fastify.addContentTypeParser('application/json', function (request, payload, done) { jsonParser(payload, function (err, body) { done(err, body) }) }) fastify.get('/hello', async (req, res) => {});});
In addition to `addContentTypeParser`, the `hasContentTypeParser`, `removeContentTypeParser`, and `removeAllContentTypeParsers` APIs are available.
#### hasContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#hascontenttypeparser "Direct link to hasContentTypeParser")
Use the `hasContentTypeParser` API to check if a specific content type parser exists.
if (!fastify.hasContentTypeParser('application/jsoff')){ fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) }) })}
#### removeContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#removecontenttypeparser "Direct link to removeContentTypeParser")
`removeContentTypeParser` can remove a single content type or an array of content types, supporting both `string` and `RegExp`.
fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Removes the both built-in content type parsers so that only the content type parser for text/html is availablefastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
The `removeAllContentTypeParsers` API removes all existing content type parsers eliminating the need to specify each one individually. This API supports encapsulation and is useful for registering a [catch-all content type parser](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#catch-all)
that should be executed for every content type, ignoring built-in parsers.
fastify.removeAllContentTypeParsers()fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})
> 🛈 Note: `function(req, done)` and `async function(req)` are still supported but deprecated.
#### Body Parser[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#body-parser "Direct link to Body Parser")
The request body can be parsed in two ways. First, add a custom content type parser and handle the request stream. Or second, use the `parseAs` option in the `addContentTypeParser` API, specifying `'string'` or `'buffer'`. Fastify will handle the stream, check the [maximum size](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-body-limit)
of the body, and the content length. If the limit is exceeded, the custom parser will not be invoked.
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) { try { const json = JSON.parse(body) done(null, json) } catch (err) { err.statusCode = 400 done(err, undefined) }})
See [`example/parser.js`](https://github.com/fastify/fastify/blob/main/examples/parser.js)
for an example.
##### Custom Parser Options[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#custom-parser-options "Direct link to Custom Parser Options")
* `parseAs` (string): `'string'` or `'buffer'` to designate how the incoming data should be collected. Default: `'buffer'`.
* `bodyLimit` (number): The maximum payload size, in bytes, that the custom parser will accept. Defaults to the global body limit passed to the [`Fastify factory function`](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit)
.
#### Catch-All[](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#catch-all "Direct link to Catch-All")
To catch all requests regardless of content type, use the `'*'` content type:
fastify.addContentTypeParser('*', function (request, payload, done) { let data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
All requests without a corresponding content type parser will be handled by this function.
This is also useful for piping the request stream. Define a content parser like:
fastify.addContentTypeParser('*', function (request, payload, done) { done()})
And then access the core HTTP request directly for piping:
app.post('/hello', (request, reply) => { reply.send(request.raw)})
Here is a complete example that logs incoming [json line](https://jsonlines.org/)
objects:
const split2 = require('split2')const pump = require('pump')fastify.addContentTypeParser('*', (request, payload, done) => { done(null, pump(payload, split2(JSON.parse)))})fastify.route({ method: 'POST', url: '/api/log/jsons', handler: (req, res) => { req.body.on('data', d => console.log(d)) // log every incoming object }})
For piping file uploads, check out [`@fastify/multipart`](https://github.com/fastify/fastify-multipart)
.
To execute the content type parser on all content types, call `removeAllContentTypeParsers` first.
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parserfastify.removeAllContentTypeParsers()fastify.addContentTypeParser('*', function (request, payload, done) { const data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
* [`Content-Type` Parser](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#content-type-parser)
* [Usage](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#usage)
* [Using addContentTypeParser with fastify.register](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister)
---
# Logging | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Logging/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Logging[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#logging "Direct link to Logging")
------------------------------------------------------------------------------------------------
### Enable Logging[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#enable-logging "Direct link to Enable Logging")
Logging is disabled by default. Enable it by passing `{ logger: true }` or `{ logger: { level: 'info' } }` when creating a Fastify instance. Note that if the logger is disabled, it cannot be enabled at runtime. [abstract-logging](https://www.npmjs.com/package/abstract-logging)
is used for this purpose.
As Fastify is focused on performance, it uses [pino](https://github.com/pinojs/pino)
as its logger, with the default log level set to `'info'` when enabled.
#### Basic logging setup[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#basic-logging-setup "Direct link to Basic logging setup")
Enabling the production JSON logger:
const fastify = require('fastify')({ logger: true})
#### Environment-Specific Configuration[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#environment-specific-configuration "Direct link to Environment-Specific Configuration")
Enabling the logger with appropriate configuration for local development, production, and test environments requires more configuration:
const envToLogger = { development: { transport: { target: 'pino-pretty', options: { translateTime: 'HH:MM:ss Z', ignore: 'pid,hostname', }, }, }, production: true, test: false,}const fastify = require('fastify')({ logger: envToLogger[environment] ?? true // defaults to true if no entry matches in the map})
⚠️ `pino-pretty` needs to be installed as a dev dependency. It is not included by default for performance reasons.
### Usage[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#usage "Direct link to Usage")
The logger can be used in route handlers as follows:
fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
Trigger new logs outside route handlers using the Pino instance from the Fastify instance:
fastify.log.info('Something important happened!');
#### Passing Logger Options[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#passing-logger-options "Direct link to Passing Logger Options")
To pass options to the logger, provide them to Fastify. See the [Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options)
for available options. To specify a file destination, use:
const fastify = require('fastify')({ logger: { level: 'info', file: '/path/to/file' // Will use pino.destination() }})fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
To pass a custom stream to the Pino instance, add a `stream` field to the logger object:
const split = require('split2')const stream = split(JSON.parse)const fastify = require('fastify')({ logger: { level: 'info', stream: stream }})
### Advanced Logger Configuration[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#advanced-logger-configuration "Direct link to Advanced Logger Configuration")
#### Request ID Tracking[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#request-id-tracking "Direct link to Request ID Tracking")
By default, Fastify adds an ID to every request for easier tracking. If the `requestIdHeader` option is set and the corresponding header is present, its value is used; otherwise, a new incremental ID is generated. See Fastify Factory [`requestIdHeader`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-request-id-header)
and Fastify Factory [`genReqId`](https://fastify.dev/docs/v5.4.x/Reference/Server/#genreqid)
for customization options.
#### Serializers[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#serializers "Direct link to Serializers")
The default logger uses standard serializers for objects with `req`, `res`, and `err` properties. The `req` object is the Fastify [`Request`](https://fastify.dev/docs/v5.4.x/Reference/Request/)
object, and the `res` object is the Fastify [`Reply`](https://fastify.dev/docs/v5.4.x/Reference/Reply/)
object. This behavior can be customized with custom serializers.
const fastify = require('fastify')({ logger: { serializers: { req (request) { return { url: request.url } } } }})
For example, the response payload and headers could be logged using the approach below (not recommended):
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode } }, req (request) { return { method: request.method, url: request.url, path: request.routeOptions.url, parameters: request.params, // Including headers in the log could violate privacy laws, // e.g., GDPR. Use the "redact" option to remove sensitive // fields. It could also leak authentication data in the logs. headers: request.headers }; } } }});
> ℹ️ Note: In some cases, the [`Reply`](https://fastify.dev/docs/v5.4.x/Reference/Reply/)
> object passed to the `res` serializer cannot be fully constructed. When writing a custom `res` serializer, check for the existence of any properties on `reply` aside from `statusCode`, which is always present. For example, verify the existence of `getHeaders` before calling it:
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode, headers: typeof reply.getHeaders === 'function' ? reply.getHeaders() : {} } }, } }});
> ℹ️ Note: The body cannot be serialized inside a `req` method because the request is serialized when the child logger is created. At that time, the body is not yet parsed.
See the following approach to log `req.body`:
app.addHook('preHandler', function (req, reply, done) { if (req.body) { req.log.info({ body: req.body }, 'parsed body') } done()})
> ℹ️ Note: Ensure serializers never throw errors, as this can cause the Node process to exit. See the [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers)
> for more information.
_Any logger other than Pino will ignore this option._
### Using Custom Loggers[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#using-custom-loggers "Direct link to Using Custom Loggers")
A custom logger instance can be supplied by passing it as `loggerInstance`. The logger must conform to the Pino interface, with methods: `info`, `error`, `debug`, `fatal`, `warn`, `trace`, `silent`, `child`, and a string property `level`.
Example:
const log = require('pino')({ level: 'info' })const fastify = require('fastify')({ loggerInstance: log })log.info('does not have request information')fastify.get('/', function (request, reply) { request.log.info('includes request information, but is the same logger instance as `log`') reply.send({ hello: 'world' })})
_The logger instance for the current request is available in every part of the [lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/)
._
### Log Redaction[](https://fastify.dev/docs/v5.4.x/Reference/Logging/#log-redaction "Direct link to Log Redaction")
[Pino](https://getpino.io/)
supports low-overhead log redaction for obscuring values of specific properties in recorded logs. For example, log all HTTP headers except the `Authorization` header for security:
const fastify = Fastify({ logger: { stream: stream, redact: ['req.headers.authorization'], level: 'info', serializers: { req (request) { return { method: request.method, url: request.url, headers: request.headers, host: request.host, remoteAddress: request.ip, remotePort: request.socket.remotePort } } } }})
See [https://getpino.io/#/docs/redaction](https://getpino.io/#/docs/redaction)
for more details.
* [Logging](https://fastify.dev/docs/v5.4.x/Reference/Logging/#logging)
* [Enable Logging](https://fastify.dev/docs/v5.4.x/Reference/Logging/#enable-logging)
* [Usage](https://fastify.dev/docs/v5.4.x/Reference/Logging/#usage)
* [Advanced Logger Configuration](https://fastify.dev/docs/v5.4.x/Reference/Logging/#advanced-logger-configuration)
* [Using Custom Loggers](https://fastify.dev/docs/v5.4.x/Reference/Logging/#using-custom-loggers)
* [Log Redaction](https://fastify.dev/docs/v5.4.x/Reference/Logging/#log-redaction)
---
# Lifecycle | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Lifecycle/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Lifecycle[](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#lifecycle "Direct link to Lifecycle")
--------------------------------------------------------------------------------------------------------
This schema shows the internal lifecycle of Fastify.
The right branch of each section shows the next phase of the lifecycle. The left branch shows the corresponding error code generated if the parent throws an error. All errors are automatically handled by Fastify.
Incoming Request │ └─▶ Routing │ └─▶ Instance Logger │ 4**/5** ◀─┴─▶ onRequest Hook │ 4**/5** ◀─┴─▶ preParsing Hook │ 4**/5** ◀─┴─▶ Parsing │ 4**/5** ◀─┴─▶ preValidation Hook │ 400 ◀─┴─▶ Validation │ 4**/5** ◀─┴─▶ preHandler Hook │ 4**/5** ◀─┴─▶ User Handler │ └─▶ Reply │ 4**/5** ◀─┴─▶ preSerialization Hook │ └─▶ onSend Hook │ 4**/5** ◀─┴─▶ Outgoing Response │ └─▶ onResponse Hook
Before or during the `User Handler`, `reply.hijack()` can be called to:
* Prevent Fastify from running subsequent hooks and the user handler
* Prevent Fastify from sending the response automatically
If `reply.raw` is used to send a response, `onResponse` hooks will still be executed.
Reply Lifecycle[](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#reply-lifecycle "Direct link to Reply Lifecycle")
--------------------------------------------------------------------------------------------------------------------------
When the user handles the request, the result may be:
* In an async handler: it returns a payload or throws an `Error`
* In a sync handler: it sends a payload or an `Error` instance
If the reply was hijacked, all subsequent steps are skipped. Otherwise, when submitted, the data flow is as follows:
★ schema validation Error │ └─▶ schemaErrorFormatter │ reply sent ◀── JSON ─┴─ Error instance │ │ ★ throw an Error ★ send or return │ │ │ │ │ │ ▼ │ reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler ◀─────┘ │ reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook │ └─▶ reply sent
`reply sent` means the JSON payload will be serialized by one of the following:
* The [reply serializer](https://fastify.dev/docs/v5.3.x/Reference/Server/#setreplyserializer)
if set
* The [serializer compiler](https://fastify.dev/docs/v5.3.x/Reference/Server/#setserializercompiler)
if a JSON schema is set for the HTTP status code
* The default `JSON.stringify` function
* [Lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#lifecycle)
* [Reply Lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#reply-lifecycle)
---
# Errors | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Errors/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Errors[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors "Direct link to Errors")
--------------------------------------------------------------------------------------------
**Table of contents**
* [Errors](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.4.x/Reference/Errors/#error-handling-in-nodejs)
* [Uncaught Errors](https://fastify.dev/docs/v5.4.x/Reference/Errors/#uncaught-errors)
* [Catching Errors In Promises](https://fastify.dev/docs/v5.4.x/Reference/Errors/#catching-errors-in-promises)
* [Errors In Fastify](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify)
* [Errors In Input Data](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-input-data)
* [Catching Uncaught Errors In Fastify](https://fastify.dev/docs/v5.4.x/Reference/Errors/#catching-uncaught-errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fastify-error-codes)
* [FST\_ERR\_NOT\_FOUND](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_not_found)
* [FST\_ERR\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_options_not_obj)
* [FST\_ERR\_QSP\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_qsp_not_fn)
* [FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_schema_controller_bucket_opt_not_fn)
* [FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_schema_error_formatter_not_fn)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_obj)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_arr)
* [FST\_ERR\_CTP\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_already_present)
* [FST\_ERR\_CTP\_INVALID\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_invalid_type)
* [FST\_ERR\_CTP\_EMPTY\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_empty_type)
* [FST\_ERR\_CTP\_INVALID\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_invalid_handler)
* [FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_invalid_parse_type)
* [FST\_ERR\_CTP\_BODY\_TOO\_LARGE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_body_too_large)
* [FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_invalid_media_type)
* [FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_invalid_content_length)
* [FST\_ERR\_CTP\_EMPTY\_JSON\_BODY](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_empty_json_body)
* [FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_instance_already_started)
* [FST\_ERR\_INSTANCE\_ALREADY\_LISTENING](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_instance_already_listening)
* [FST\_ERR\_DEC\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_already_present)
* [FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_dependency_invalid_type)
* [FST\_ERR\_DEC\_MISSING\_DEPENDENCY](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_missing_dependency)
* [FST\_ERR\_DEC\_AFTER\_START](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_after_start)
* [FST\_ERR\_DEC\_REFERENCE\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_reference_type)
* [FST\_ERR\_DEC\_UNDECLARED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_dec_undeclared)
* [FST\_ERR\_HOOK\_INVALID\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_hook_invalid_type)
* [FST\_ERR\_HOOK\_INVALID\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_hook_invalid_handler)
* [FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_hook_invalid_async_handler)
* [FST\_ERR\_HOOK\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_hook_not_supported)
* [FST\_ERR\_MISSING\_MIDDLEWARE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_missing_middleware)
* [FST\_ERR\_HOOK\_TIMEOUT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_hook_timeout)
* [FST\_ERR\_LOG\_INVALID\_DESTINATION](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_log_invalid_destination)
* [FST\_ERR\_LOG\_INVALID\_LOGGER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_log_invalid_logger)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_log_invalid_logger_instance)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_log_invalid_logger_config)
* [FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_log_logger_and_logger_instance_provided)
* [FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_rep_invalid_payload_type)
* [FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_rep_response_body_consumed)
* [FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_rep_readable_stream_locked)
* [FST\_ERR\_REP\_ALREADY\_SENT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_rep_already_sent)
* [FST\_ERR\_REP\_SENT\_VALUE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_rep_sent_value)
* [FST\_ERR\_SEND\_INSIDE\_ONERR](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_send_inside_onerr)
* [FST\_ERR\_SEND\_UNDEFINED\_ERR](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_send_undefined_err)
* [FST\_ERR\_BAD\_STATUS\_CODE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_bad_status_code)
* [FST\_ERR\_BAD\_TRAILER\_NAME](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_bad_trailer_name)
* [FST\_ERR\_BAD\_TRAILER\_VALUE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_bad_trailer_value)
* [FST\_ERR\_FAILED\_ERROR\_SERIALIZATION](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_failed_error_serialization)
* [FST\_ERR\_MISSING\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_missing_serialization_fn)
* [FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_missing_contenttype_serialization_fn)
* [FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_req_invalid_validation_invocation)
* [FST\_ERR\_SCH\_MISSING\_ID](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_missing_id)
* [FST\_ERR\_SCH\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_already_present)
* [FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_content_missing_schema)
* [FST\_ERR\_SCH\_DUPLICATE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_duplicate)
* [FST\_ERR\_SCH\_VALIDATION\_BUILD](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_validation_build)
* [FST\_ERR\_SCH\_SERIALIZATION\_BUILD](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_serialization_build)
* [FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_sch_response_schema_not_nested_2xx)
* [FST\_ERR\_INIT\_OPTS\_INVALID](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_init_opts_invalid)
* [FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_force_close_connections_idle_not_available)
* [FST\_ERR\_DUPLICATED\_ROUTE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_duplicated_route)
* [FST\_ERR\_BAD\_URL](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_bad_url)
* [FST\_ERR\_ASYNC\_CONSTRAINT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_async_constraint)
* [FST\_ERR\_INVALID\_URL](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_invalid_url)
* [FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_options_not_obj)
* [FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_duplicated_handler)
* [FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_handler_not_fn)
* [FST\_ERR\_ROUTE\_MISSING\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_missing_handler)
* [FST\_ERR\_ROUTE\_METHOD\_INVALID](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_method_invalid)
* [FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_method_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_body_validation_schema_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_body_limit_option_not_int)
* [FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_route_rewrite_not_str)
* [FST\_ERR\_REOPENED\_CLOSE\_SERVER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_reopened_close_server)
* [FST\_ERR\_REOPENED\_SERVER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_reopened_server)
* [FST\_ERR\_PLUGIN\_VERSION\_MISMATCH](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_version_mismatch)
* [FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_callback_not_fn)
* [FST\_ERR\_PLUGIN\_NOT\_VALID](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_not_valid)
* [FST\_ERR\_ROOT\_PLG\_BOOTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_root_plg_booted)
* [FST\_ERR\_PARENT\_PLUGIN\_BOOTED](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_parent_plugin_booted)
* [FST\_ERR\_PLUGIN\_TIMEOUT](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_timeout)
* [FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_not_present_in_instance)
* [FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_plugin_invalid_async_handler)
* [FST\_ERR\_VALIDATION](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_validation)
* [FST\_ERR\_LISTEN\_OPTIONS\_INVALID](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_listen_options_invalid)
* [FST\_ERR\_ERROR\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_error_handler_not_fn)
* [FST\_ERR\_ERROR\_HANDLER\_ALREADY\_SET](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_error_handler_already_set)
### Error Handling In Node.js[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#error-handling-in-nodejs "Direct link to Error Handling In Node.js")
#### Uncaught Errors[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#uncaught-errors "Direct link to Uncaught Errors")
In Node.js, uncaught errors can cause memory leaks, file descriptor leaks, and other major production issues. [Domains](https://nodejs.org/en/docs/guides/domain-postmortem/)
were a failed attempt to fix this.
Given that it is not possible to process all uncaught errors sensibly, the best way to deal with them is to [crash](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly)
.
#### Catching Errors In Promises[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#catching-errors-in-promises "Direct link to Catching Errors In Promises")
When using promises, attach a `.catch()` handler synchronously.
### Errors In Fastify[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify "Direct link to Errors In Fastify")
Fastify follows an all-or-nothing approach and aims to be lean and optimal. The developer is responsible for ensuring errors are handled properly.
#### Errors In Input Data[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-input-data "Direct link to Errors In Input Data")
Most errors result from unexpected input data, so it is recommended to [validate input data against a JSON schema](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/)
.
#### Catching Uncaught Errors In Fastify[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#catching-uncaught-errors-in-fastify "Direct link to Catching Uncaught Errors In Fastify")
Fastify tries to catch as many uncaught errors as possible without hindering performance. This includes:
1. synchronous routes, e.g. `app.get('/', () => { throw new Error('kaboom') })`
2. `async` routes, e.g. `app.get('/', async () => { throw new Error('kaboom') })`
In both cases, the error will be caught safely and routed to Fastify's default error handler, resulting in a generic `500 Internal Server Error` response.
To customize this behavior, use [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
.
### Errors In Fastify Lifecycle Hooks And A Custom Error Handler[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler "Direct link to Errors In Fastify Lifecycle Hooks And A Custom Error Handler")
From the [Hooks documentation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#manage-errors-from-a-hook)
:
> If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
When a custom error handler is defined through [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
, it will receive the error passed to the `done()` callback or through other supported automatic error handling mechanisms. If `setErrorHandler` is used multiple times, the error will be routed to the most precedent handler within the error [encapsulation context](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/)
. Error handlers are fully encapsulated, so a `setErrorHandler` call within a plugin will limit the error handler to that plugin's context.
The root error handler is Fastify's generic error handler. This error handler will use the headers and status code in the `Error` object, if they exist. The headers and status code will not be automatically set if a custom error handler is provided.
The following should be considered when using a custom error handler:
* `reply.send(data)` behaves as in [regular route handlers](https://fastify.dev/docs/v5.4.x/Reference/Reply/#senddata)
* objects are serialized, triggering the `preSerialization` lifecycle hook if defined
* strings, buffers, and streams are sent to the client with appropriate headers (no serialization)
* Throwing a new error in a custom error handler will call the parent `errorHandler`.
* The `onError` hook will be triggered once for the first error thrown
* An error will not be triggered twice from a lifecycle hook. Fastify internally monitors error invocation to avoid infinite loops for errors thrown in the reply phases of the lifecycle (those after the route handler)
When using Fastify's custom error handling through [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
, be aware of how errors are propagated between custom and default error handlers.
If a plugin's error handler re-throws an error that is not an instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
, it will not propagate to the parent context error handler. Instead, it will be caught by the default error handler. This can be seen in the `/bad` route of the example below.
To ensure consistent error handling, throw instances of `Error`. For example, replace `throw 'foo'` with `throw new Error('foo')` in the `/bad` route to ensure errors propagate through the custom error handling chain as intended. This practice helps avoid potential pitfalls when working with custom error handling in Fastify.
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Register parent error handlerfastify.setErrorHandler((error, request, reply) => { reply.status(500).send({ ok: false })})fastify.register((app, options, next) => { // Register child error handler fastify.setErrorHandler((error, request, reply) => { throw error }) fastify.get('/bad', async () => { // Throws a non-Error type, 'bar' throw 'foo' }) fastify.get('/good', async () => { // Throws an Error instance, 'bar' throw new Error('bar') }) next()})// Run the serverfastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is listening at ${address}})
### Fastify Error Codes[](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fastify-error-codes "Direct link to Fastify Error Codes")
You can access `errorCodes` for mapping:
// ESMimport { errorCodes } from 'fastify'// CommonJSconst errorCodes = require('fastify').errorCodes
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Declare a routefastify.get('/', function (request, reply) { reply.code('bad status code').send({ hello: 'world' })})fastify.setErrorHandler(function (error, request, reply) { if (error instanceof Fastify.errorCodes.FST_ERR_BAD_STATUS_CODE) { // Log error this.log.error(error) // Send error response reply.status(500).send({ ok: false }) } else { // Fastify will use parent error handler to handle this reply.send(error) }})// Run the server!fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
Below is a table with all the error codes used by Fastify.
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
| FST\_ERR\_NOT\_FOUND | 404 Not Found | \- | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_OPTIONS\_NOT\_OBJ | Fastify options wrongly specified. | Fastify options should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_QSP\_NOT\_FN | QueryStringParser wrongly specified. | QueryStringParser option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN | SchemaController.bucket wrongly specified. | SchemaController.bucket option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN | SchemaErrorFormatter option wrongly specified. | SchemaErrorFormatter option should be a non async function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ | ajv.customOptions wrongly specified. | ajv.customOptions option should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR | ajv.plugins option wrongly specified. | ajv.plugins option should be an array. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_CTP\_ALREADY\_PRESENT | The parser for this content type was already registered. | Use a different content type or delete the already registered parser. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_TYPE | `Content-Type` wrongly specified | The `Content-Type` should be a string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_TYPE | `Content-Type` is an empty string. | `Content-Type` cannot be an empty string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_HANDLER | Invalid handler for the content type. | Use a different handler. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE | The provided parse type is not supported. | Accepted values are `string` or `buffer`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_BODY\_TOO\_LARGE | The request body is larger than the provided limit. | Increase the limit in the Fastify server instance setting: [bodyLimit](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit) | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE | The received media type is not supported (i.e. there is no suitable `Content-Type` parser for it). | Use a different content type. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH | Request body size did not match `Content-Length`. | Check the request body size and the `Content-Length` header. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_JSON\_BODY | Body cannot be empty when content-type is set to `application/json`. | Check the request body. | [#1253](https://github.com/fastify/fastify/pull/1253) |
| FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED | Fastify is already started. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_INSTANCE\_ALREADY\_LISTENING | Fastify instance is already listening. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_DEC\_ALREADY\_PRESENT | A decorator with the same name is already registered. | Use a different decorator name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE | The dependencies of decorator must be of type `Array`. | Use an array for the dependencies. | [#3090](https://github.com/fastify/fastify/pull/3090) |
| FST\_ERR\_DEC\_MISSING\_DEPENDENCY | The decorator cannot be registered due to a missing dependency. | Register the missing dependency. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_AFTER\_START | The decorator cannot be added after start. | Add the decorator before starting the server. | [#2128](https://github.com/fastify/fastify/pull/2128) |
| FST\_ERR\_DEC\_REFERENCE\_TYPE | The decorator cannot be a reference type. | Define the decorator with a getter/setter interface or an empty decorator with a hook. | [#5462](https://github.com/fastify/fastify/pull/5462) |
| FST\_ERR\_DEC\_UNDECLARED | An attempt was made to access a decorator that has not been declared. | Declare the decorator before using it. | [#](https://github.com/fastify/fastify/pull/) |
| FST\_ERR\_HOOK\_INVALID\_TYPE | The hook name must be a string. | Use a string for the hook name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_HANDLER | The hook callback must be a function. | Use a function for the hook callback. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER | Async function has too many arguments. Async hooks should not use the `done` argument. | Remove the `done` argument from the async hook. | [#4367](https://github.com/fastify/fastify/pull/4367) |
| FST\_ERR\_HOOK\_NOT\_SUPPORTED | The hook is not supported. | Use a supported hook. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_MISSING\_MIDDLEWARE | You must register a plugin for handling middlewares, visit [`Middleware`](https://fastify.dev/docs/v5.4.x/Reference/Middleware/)
for more info. | Register a plugin for handling middlewares. | [#2014](https://github.com/fastify/fastify/pull/2014) |
| FST\_ERR\_HOOK\_TIMEOUT | A callback for a hook timed out. | Increase the timeout for the hook. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_LOG\_INVALID\_DESTINATION | The logger does not accept the specified destination. | Use a `'stream'` or a `'file'` as the destination. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_LOG\_INVALID\_LOGGER | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE | The `loggerInstance` only accepts a logger instance, not a configuration object. | To pass a configuration object, use `'logger'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG | The logger option only accepts a configuration object, not a logger instance. | To pass an instance, use `'loggerInstance'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED | You cannot provide both `'logger'` and `'loggerInstance'`. | Please provide only one option. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED | Using `Response` as reply payload, but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |
| FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED | Using `ReadableStream` as reply payload, but locked with another reader. | Make sure you don't call the `Readable.getReader` before sending or release lock with `reader.releaseLock()` before sending. | [#5920](https://github.com/fastify/fastify/pull/5920) |
| FST\_ERR\_REP\_ALREADY\_SENT | A response was already sent. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_REP\_SENT\_VALUE | The only possible value for `reply.sent` is `true`. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_SEND\_INSIDE\_ONERR | You cannot use `send` inside the `onError` hook. | \- | [#1348](https://github.com/fastify/fastify/pull/1348) |
| FST\_ERR\_SEND\_UNDEFINED\_ERR | Undefined error has occurred. | \- | [#2074](https://github.com/fastify/fastify/pull/2074) |
| FST\_ERR\_BAD\_STATUS\_CODE | The status code is not valid. | Use a valid status code. | [#2082](https://github.com/fastify/fastify/pull/2082) |
| FST\_ERR\_BAD\_TRAILER\_NAME | Called `reply.trailer` with an invalid header name. | Use a valid header name. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_BAD\_TRAILER\_VALUE | Called `reply.trailer` with an invalid type. Expected a function. | Use a function. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_FAILED\_ERROR\_SERIALIZATION | Failed to serialize an error. | \- | [#4601](https://github.com/fastify/fastify/pull/4601) |
| FST\_ERR\_MISSING\_SERIALIZATION\_FN | Missing serialization function. | Add a serialization function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN | Missing `Content-Type` serialization function. | Add a serialization function. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION | Invalid validation invocation. Missing validation function for HTTP part nor schema provided. | Add a validation function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_SCH\_MISSING\_ID | The schema provided does not have `$id` property. | Add a `$id` property. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_ALREADY\_PRESENT | A schema with the same `$id` already exists. | Use a different `$id`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA | A schema is missing for the corresponding content type. | Add a schema. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_SCH\_DUPLICATE | Schema with the same attribute already present! | Use a different attribute. | [#1954](https://github.com/fastify/fastify/pull/1954) |
| FST\_ERR\_SCH\_VALIDATION\_BUILD | The JSON schema provided for validation to a route is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_SERIALIZATION\_BUILD | The JSON schema provided for serialization of a route response is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX | Response schemas should be nested under a valid status code (2XX). | Use a valid status code. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_INIT\_OPTS\_INVALID | Invalid initialization options. | Use valid initialization options. | [#1471](https://github.com/fastify/fastify/pull/1471) |
| FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE | Cannot set forceCloseConnections to `idle` as your HTTP server does not support `closeIdleConnections` method. | Use a different value for `forceCloseConnections`. | [#3925](https://github.com/fastify/fastify/pull/3925) |
| FST\_ERR\_DUPLICATED\_ROUTE | The HTTP method already has a registered controller for that URL. | Use a different URL or register the controller for another HTTP method. | [#2954](https://github.com/fastify/fastify/pull/2954) |
| FST\_ERR\_BAD\_URL | The router received an invalid URL. | Use a valid URL. | [#2106](https://github.com/fastify/fastify/pull/2106) |
| FST\_ERR\_ASYNC\_CONSTRAINT | The router received an error when using asynchronous constraints. | \- | [#4323](https://github.com/fastify/fastify/pull/4323) |
| FST\_ERR\_INVALID\_URL | URL must be a string. | Use a string for the URL. | [#3653](https://github.com/fastify/fastify/pull/3653) |
| FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ | Options for the route must be an object. | Use an object for the route options. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER | Duplicate handler for the route is not allowed. | Use a different handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN | Handler for the route must be a function. | Use a function for the handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_MISSING\_HANDLER | Missing handler function for the route. | Add a handler function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_METHOD\_INVALID | Method is not a valid value. | Use a valid value for the method. | [#4750](https://github.com/fastify/fastify/pull/4750) |
| FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED | Method is not supported for the route. | Use a supported method. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED | Body validation schema route is not supported. | Use a different different method for the route. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT | `bodyLimit` option must be an integer. | Use an integer for the `bodyLimit` option. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR | `rewriteUrl` needs to be of type `string`. | Use a string for the `rewriteUrl`. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_REOPENED\_CLOSE\_SERVER | Fastify has already been closed and cannot be reopened. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_REOPENED\_SERVER | Fastify is already listening. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_PLUGIN\_VERSION\_MISMATCH | Installed Fastify plugin mismatched expected version. | Use a compatible version of the plugin. | [#2549](https://github.com/fastify/fastify/pull/2549) |
| FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN | Callback for a hook is not a function. | Use a function for the callback. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_VALID | Plugin must be a function or a promise. | Use a function or a promise for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_ROOT\_PLG\_BOOTED | Root plugin has already booted. | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PARENT\_PLUGIN\_BOOTED | Impossible to load plugin because the parent (mapped directly from `avvio`) | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_TIMEOUT | Plugin did not start in time. | Increase the timeout for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE | The decorator is not present in the instance. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER | The plugin being registered mixes async and callback styles. | \- | [#5141](https://github.com/fastify/fastify/pull/5141) |
| FST\_ERR\_VALIDATION | The Request failed the payload validation. | Check the request payload. | [#4824](https://github.com/fastify/fastify/pull/4824) |
| FST\_ERR\_LISTEN\_OPTIONS\_INVALID | Invalid listen options. | Check the listen options. | [#4886](https://github.com/fastify/fastify/pull/4886) |
| FST\_ERR\_ERROR\_HANDLER\_NOT\_FN | Error Handler must be a function | Provide a function to `setErrorHandler`. | [#5317](https://github.com/fastify/fastify/pull/5317) |
* [Errors](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.4.x/Reference/Errors/#error-handling-in-nodejs)
* [Errors In Fastify](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.4.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fastify-error-codes)
---
# Errors | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Errors/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Errors/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Errors[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors "Direct link to Errors")
--------------------------------------------------------------------------------------------
**Table of contents**
* [Errors](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.3.x/Reference/Errors/#error-handling-in-nodejs)
* [Uncaught Errors](https://fastify.dev/docs/v5.3.x/Reference/Errors/#uncaught-errors)
* [Catching Errors In Promises](https://fastify.dev/docs/v5.3.x/Reference/Errors/#catching-errors-in-promises)
* [Errors In Fastify](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify)
* [Errors In Input Data](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-input-data)
* [Catching Uncaught Errors In Fastify](https://fastify.dev/docs/v5.3.x/Reference/Errors/#catching-uncaught-errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fastify-error-codes)
* [FST\_ERR\_NOT\_FOUND](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_not_found)
* [FST\_ERR\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_options_not_obj)
* [FST\_ERR\_QSP\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_qsp_not_fn)
* [FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_schema_controller_bucket_opt_not_fn)
* [FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_schema_error_formatter_not_fn)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_obj)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_arr)
* [FST\_ERR\_CTP\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_already_present)
* [FST\_ERR\_CTP\_INVALID\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_invalid_type)
* [FST\_ERR\_CTP\_EMPTY\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_empty_type)
* [FST\_ERR\_CTP\_INVALID\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_invalid_handler)
* [FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_invalid_parse_type)
* [FST\_ERR\_CTP\_BODY\_TOO\_LARGE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_body_too_large)
* [FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_invalid_media_type)
* [FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_invalid_content_length)
* [FST\_ERR\_CTP\_EMPTY\_JSON\_BODY](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_empty_json_body)
* [FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_instance_already_started)
* [FST\_ERR\_INSTANCE\_ALREADY\_LISTENING](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_instance_already_listening)
* [FST\_ERR\_DEC\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_already_present)
* [FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_dependency_invalid_type)
* [FST\_ERR\_DEC\_MISSING\_DEPENDENCY](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_missing_dependency)
* [FST\_ERR\_DEC\_AFTER\_START](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_after_start)
* [FST\_ERR\_DEC\_REFERENCE\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_reference_type)
* [FST\_ERR\_DEC\_UNDECLARED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_dec_undeclared)
* [FST\_ERR\_HOOK\_INVALID\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_hook_invalid_type)
* [FST\_ERR\_HOOK\_INVALID\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_hook_invalid_handler)
* [FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_hook_invalid_async_handler)
* [FST\_ERR\_HOOK\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_hook_not_supported)
* [FST\_ERR\_MISSING\_MIDDLEWARE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_missing_middleware)
* [FST\_ERR\_HOOK\_TIMEOUT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_hook_timeout)
* [FST\_ERR\_LOG\_INVALID\_DESTINATION](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_log_invalid_destination)
* [FST\_ERR\_LOG\_INVALID\_LOGGER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_log_invalid_logger)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_log_invalid_logger_instance)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_log_invalid_logger_config)
* [FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_log_logger_and_logger_instance_provided)
* [FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_rep_invalid_payload_type)
* [FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_rep_response_body_consumed)
* [FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_rep_readable_stream_locked)
* [FST\_ERR\_REP\_ALREADY\_SENT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_rep_already_sent)
* [FST\_ERR\_REP\_SENT\_VALUE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_rep_sent_value)
* [FST\_ERR\_SEND\_INSIDE\_ONERR](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_send_inside_onerr)
* [FST\_ERR\_SEND\_UNDEFINED\_ERR](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_send_undefined_err)
* [FST\_ERR\_BAD\_STATUS\_CODE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_bad_status_code)
* [FST\_ERR\_BAD\_TRAILER\_NAME](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_bad_trailer_name)
* [FST\_ERR\_BAD\_TRAILER\_VALUE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_bad_trailer_value)
* [FST\_ERR\_FAILED\_ERROR\_SERIALIZATION](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_failed_error_serialization)
* [FST\_ERR\_MISSING\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_missing_serialization_fn)
* [FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_missing_contenttype_serialization_fn)
* [FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_req_invalid_validation_invocation)
* [FST\_ERR\_SCH\_MISSING\_ID](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_missing_id)
* [FST\_ERR\_SCH\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_already_present)
* [FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_content_missing_schema)
* [FST\_ERR\_SCH\_DUPLICATE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_duplicate)
* [FST\_ERR\_SCH\_VALIDATION\_BUILD](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_validation_build)
* [FST\_ERR\_SCH\_SERIALIZATION\_BUILD](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_serialization_build)
* [FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_sch_response_schema_not_nested_2xx)
* [FST\_ERR\_INIT\_OPTS\_INVALID](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_init_opts_invalid)
* [FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_force_close_connections_idle_not_available)
* [FST\_ERR\_DUPLICATED\_ROUTE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_duplicated_route)
* [FST\_ERR\_BAD\_URL](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_bad_url)
* [FST\_ERR\_ASYNC\_CONSTRAINT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_async_constraint)
* [FST\_ERR\_INVALID\_URL](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_invalid_url)
* [FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_options_not_obj)
* [FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_duplicated_handler)
* [FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_handler_not_fn)
* [FST\_ERR\_ROUTE\_MISSING\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_missing_handler)
* [FST\_ERR\_ROUTE\_METHOD\_INVALID](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_method_invalid)
* [FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_method_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_body_validation_schema_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_body_limit_option_not_int)
* [FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_route_rewrite_not_str)
* [FST\_ERR\_REOPENED\_CLOSE\_SERVER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_reopened_close_server)
* [FST\_ERR\_REOPENED\_SERVER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_reopened_server)
* [FST\_ERR\_PLUGIN\_VERSION\_MISMATCH](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_version_mismatch)
* [FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_callback_not_fn)
* [FST\_ERR\_PLUGIN\_NOT\_VALID](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_not_valid)
* [FST\_ERR\_ROOT\_PLG\_BOOTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_root_plg_booted)
* [FST\_ERR\_PARENT\_PLUGIN\_BOOTED](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_parent_plugin_booted)
* [FST\_ERR\_PLUGIN\_TIMEOUT](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_timeout)
* [FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_not_present_in_instance)
* [FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_plugin_invalid_async_handler)
* [FST\_ERR\_VALIDATION](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_validation)
* [FST\_ERR\_LISTEN\_OPTIONS\_INVALID](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_listen_options_invalid)
* [FST\_ERR\_ERROR\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_error_handler_not_fn)
### Error Handling In Node.js[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#error-handling-in-nodejs "Direct link to Error Handling In Node.js")
#### Uncaught Errors[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#uncaught-errors "Direct link to Uncaught Errors")
In Node.js, uncaught errors can cause memory leaks, file descriptor leaks, and other major production issues. [Domains](https://nodejs.org/en/docs/guides/domain-postmortem/)
were a failed attempt to fix this.
Given that it is not possible to process all uncaught errors sensibly, the best way to deal with them is to [crash](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly)
.
#### Catching Errors In Promises[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#catching-errors-in-promises "Direct link to Catching Errors In Promises")
When using promises, attach a `.catch()` handler synchronously.
### Errors In Fastify[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify "Direct link to Errors In Fastify")
Fastify follows an all-or-nothing approach and aims to be lean and optimal. The developer is responsible for ensuring errors are handled properly.
#### Errors In Input Data[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-input-data "Direct link to Errors In Input Data")
Most errors result from unexpected input data, so it is recommended to [validate input data against a JSON schema](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/)
.
#### Catching Uncaught Errors In Fastify[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#catching-uncaught-errors-in-fastify "Direct link to Catching Uncaught Errors In Fastify")
Fastify tries to catch as many uncaught errors as possible without hindering performance. This includes:
1. synchronous routes, e.g. `app.get('/', () => { throw new Error('kaboom') })`
2. `async` routes, e.g. `app.get('/', async () => { throw new Error('kaboom') })`
In both cases, the error will be caught safely and routed to Fastify's default error handler, resulting in a generic `500 Internal Server Error` response.
To customize this behavior, use [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
.
### Errors In Fastify Lifecycle Hooks And A Custom Error Handler[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler "Direct link to Errors In Fastify Lifecycle Hooks And A Custom Error Handler")
From the [Hooks documentation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#manage-errors-from-a-hook)
:
> If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
When a custom error handler is defined through [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
, it will receive the error passed to the `done()` callback or through other supported automatic error handling mechanisms. If `setErrorHandler` is used multiple times, the error will be routed to the most precedent handler within the error [encapsulation context](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/)
. Error handlers are fully encapsulated, so a `setErrorHandler` call within a plugin will limit the error handler to that plugin's context.
The root error handler is Fastify's generic error handler. This error handler will use the headers and status code in the `Error` object, if they exist. The headers and status code will not be automatically set if a custom error handler is provided.
The following should be considered when using a custom error handler:
* `reply.send(data)` behaves as in [regular route handlers](https://fastify.dev/docs/v5.3.x/Reference/Reply/#senddata)
* objects are serialized, triggering the `preSerialization` lifecycle hook if defined
* strings, buffers, and streams are sent to the client with appropriate headers (no serialization)
* Throwing a new error in a custom error handler will call the parent `errorHandler`.
* The `onError` hook will be triggered once for the first error thrown
* An error will not be triggered twice from a lifecycle hook. Fastify internally monitors error invocation to avoid infinite loops for errors thrown in the reply phases of the lifecycle (those after the route handler)
When using Fastify's custom error handling through [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
, be aware of how errors are propagated between custom and default error handlers.
If a plugin's error handler re-throws an error that is not an instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
, it will not propagate to the parent context error handler. Instead, it will be caught by the default error handler. This can be seen in the `/bad` route of the example below.
To ensure consistent error handling, throw instances of `Error`. For example, replace `throw 'foo'` with `throw new Error('foo')` in the `/bad` route to ensure errors propagate through the custom error handling chain as intended. This practice helps avoid potential pitfalls when working with custom error handling in Fastify.
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Register parent error handlerfastify.setErrorHandler((error, request, reply) => { reply.status(500).send({ ok: false })})fastify.register((app, options, next) => { // Register child error handler fastify.setErrorHandler((error, request, reply) => { throw error }) fastify.get('/bad', async () => { // Throws a non-Error type, 'bar' throw 'foo' }) fastify.get('/good', async () => { // Throws an Error instance, 'bar' throw new Error('bar') }) next()})// Run the serverfastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is listening at ${address}})
### Fastify Error Codes[](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fastify-error-codes "Direct link to Fastify Error Codes")
You can access `errorCodes` for mapping:
// ESMimport { errorCodes } from 'fastify'// CommonJSconst errorCodes = require('fastify').errorCodes
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Declare a routefastify.get('/', function (request, reply) { reply.code('bad status code').send({ hello: 'world' })})fastify.setErrorHandler(function (error, request, reply) { if (error instanceof Fastify.errorCodes.FST_ERR_BAD_STATUS_CODE) { // Log error this.log.error(error) // Send error response reply.status(500).send({ ok: false }) } else { // Fastify will use parent error handler to handle this reply.send(error) }})// Run the server!fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
Below is a table with all the error codes used by Fastify.
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
| FST\_ERR\_NOT\_FOUND | 404 Not Found | \- | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_OPTIONS\_NOT\_OBJ | Fastify options wrongly specified. | Fastify options should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_QSP\_NOT\_FN | QueryStringParser wrongly specified. | QueryStringParser option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN | SchemaController.bucket wrongly specified. | SchemaController.bucket option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN | SchemaErrorFormatter option wrongly specified. | SchemaErrorFormatter option should be a non async function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ | ajv.customOptions wrongly specified. | ajv.customOptions option should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR | ajv.plugins option wrongly specified. | ajv.plugins option should be an array. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_CTP\_ALREADY\_PRESENT | The parser for this content type was already registered. | Use a different content type or delete the already registered parser. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_TYPE | `Content-Type` wrongly specified | The `Content-Type` should be a string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_TYPE | `Content-Type` is an empty string. | `Content-Type` cannot be an empty string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_HANDLER | Invalid handler for the content type. | Use a different handler. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE | The provided parse type is not supported. | Accepted values are `string` or `buffer`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_BODY\_TOO\_LARGE | The request body is larger than the provided limit. | Increase the limit in the Fastify server instance setting: [bodyLimit](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit) | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE | The received media type is not supported (i.e. there is no suitable `Content-Type` parser for it). | Use a different content type. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH | Request body size did not match `Content-Length`. | Check the request body size and the `Content-Length` header. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_JSON\_BODY | Body cannot be empty when content-type is set to `application/json`. | Check the request body. | [#1253](https://github.com/fastify/fastify/pull/1253) |
| FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED | Fastify is already started. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_INSTANCE\_ALREADY\_LISTENING | Fastify instance is already listening. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_DEC\_ALREADY\_PRESENT | A decorator with the same name is already registered. | Use a different decorator name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE | The dependencies of decorator must be of type `Array`. | Use an array for the dependencies. | [#3090](https://github.com/fastify/fastify/pull/3090) |
| FST\_ERR\_DEC\_MISSING\_DEPENDENCY | The decorator cannot be registered due to a missing dependency. | Register the missing dependency. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_AFTER\_START | The decorator cannot be added after start. | Add the decorator before starting the server. | [#2128](https://github.com/fastify/fastify/pull/2128) |
| FST\_ERR\_DEC\_REFERENCE\_TYPE | The decorator cannot be a reference type. | Define the decorator with a getter/setter interface or an empty decorator with a hook. | [#5462](https://github.com/fastify/fastify/pull/5462) |
| FST\_ERR\_DEC\_UNDECLARED | An attempt was made to access a decorator that has not been declared. | Declare the decorator before using it. | [#](https://github.com/fastify/fastify/pull/) |
| FST\_ERR\_HOOK\_INVALID\_TYPE | The hook name must be a string. | Use a string for the hook name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_HANDLER | The hook callback must be a function. | Use a function for the hook callback. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER | Async function has too many arguments. Async hooks should not use the `done` argument. | Remove the `done` argument from the async hook. | [#4367](https://github.com/fastify/fastify/pull/4367) |
| FST\_ERR\_HOOK\_NOT\_SUPPORTED | The hook is not supported. | Use a supported hook. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_MISSING\_MIDDLEWARE | You must register a plugin for handling middlewares, visit [`Middleware`](https://fastify.dev/docs/v5.3.x/Reference/Middleware/)
for more info. | Register a plugin for handling middlewares. | [#2014](https://github.com/fastify/fastify/pull/2014) |
| FST\_ERR\_HOOK\_TIMEOUT | A callback for a hook timed out. | Increase the timeout for the hook. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_LOG\_INVALID\_DESTINATION | The logger does not accept the specified destination. | Use a `'stream'` or a `'file'` as the destination. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_LOG\_INVALID\_LOGGER | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE | The `loggerInstance` only accepts a logger instance, not a configuration object. | To pass a configuration object, use `'logger'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG | The logger option only accepts a configuration object, not a logger instance. | To pass an instance, use `'loggerInstance'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED | You cannot provide both `'logger'` and `'loggerInstance'`. | Please provide only one option. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED | Using `Response` as reply payload, but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |
| FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED | Using `ReadableStream` as reply payload, but locked with another reader. | Make sure you don't call the `Readable.getReader` before sending or release lock with `reader.releaseLock()` before sending. | [#5920](https://github.com/fastify/fastify/pull/5920) |
| FST\_ERR\_REP\_ALREADY\_SENT | A response was already sent. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_REP\_SENT\_VALUE | The only possible value for `reply.sent` is `true`. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_SEND\_INSIDE\_ONERR | You cannot use `send` inside the `onError` hook. | \- | [#1348](https://github.com/fastify/fastify/pull/1348) |
| FST\_ERR\_SEND\_UNDEFINED\_ERR | Undefined error has occurred. | \- | [#2074](https://github.com/fastify/fastify/pull/2074) |
| FST\_ERR\_BAD\_STATUS\_CODE | The status code is not valid. | Use a valid status code. | [#2082](https://github.com/fastify/fastify/pull/2082) |
| FST\_ERR\_BAD\_TRAILER\_NAME | Called `reply.trailer` with an invalid header name. | Use a valid header name. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_BAD\_TRAILER\_VALUE | Called `reply.trailer` with an invalid type. Expected a function. | Use a function. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_FAILED\_ERROR\_SERIALIZATION | Failed to serialize an error. | \- | [#4601](https://github.com/fastify/fastify/pull/4601) |
| FST\_ERR\_MISSING\_SERIALIZATION\_FN | Missing serialization function. | Add a serialization function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN | Missing `Content-Type` serialization function. | Add a serialization function. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION | Invalid validation invocation. Missing validation function for HTTP part nor schema provided. | Add a validation function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_SCH\_MISSING\_ID | The schema provided does not have `$id` property. | Add a `$id` property. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_ALREADY\_PRESENT | A schema with the same `$id` already exists. | Use a different `$id`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA | A schema is missing for the corresponding content type. | Add a schema. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_SCH\_DUPLICATE | Schema with the same attribute already present! | Use a different attribute. | [#1954](https://github.com/fastify/fastify/pull/1954) |
| FST\_ERR\_SCH\_VALIDATION\_BUILD | The JSON schema provided for validation to a route is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_SERIALIZATION\_BUILD | The JSON schema provided for serialization of a route response is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX | Response schemas should be nested under a valid status code (2XX). | Use a valid status code. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_INIT\_OPTS\_INVALID | Invalid initialization options. | Use valid initialization options. | [#1471](https://github.com/fastify/fastify/pull/1471) |
| FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE | Cannot set forceCloseConnections to `idle` as your HTTP server does not support `closeIdleConnections` method. | Use a different value for `forceCloseConnections`. | [#3925](https://github.com/fastify/fastify/pull/3925) |
| FST\_ERR\_DUPLICATED\_ROUTE | The HTTP method already has a registered controller for that URL. | Use a different URL or register the controller for another HTTP method. | [#2954](https://github.com/fastify/fastify/pull/2954) |
| FST\_ERR\_BAD\_URL | The router received an invalid URL. | Use a valid URL. | [#2106](https://github.com/fastify/fastify/pull/2106) |
| FST\_ERR\_ASYNC\_CONSTRAINT | The router received an error when using asynchronous constraints. | \- | [#4323](https://github.com/fastify/fastify/pull/4323) |
| FST\_ERR\_INVALID\_URL | URL must be a string. | Use a string for the URL. | [#3653](https://github.com/fastify/fastify/pull/3653) |
| FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ | Options for the route must be an object. | Use an object for the route options. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER | Duplicate handler for the route is not allowed. | Use a different handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN | Handler for the route must be a function. | Use a function for the handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_MISSING\_HANDLER | Missing handler function for the route. | Add a handler function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_METHOD\_INVALID | Method is not a valid value. | Use a valid value for the method. | [#4750](https://github.com/fastify/fastify/pull/4750) |
| FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED | Method is not supported for the route. | Use a supported method. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED | Body validation schema route is not supported. | Use a different different method for the route. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT | `bodyLimit` option must be an integer. | Use an integer for the `bodyLimit` option. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR | `rewriteUrl` needs to be of type `string`. | Use a string for the `rewriteUrl`. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_REOPENED\_CLOSE\_SERVER | Fastify has already been closed and cannot be reopened. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_REOPENED\_SERVER | Fastify is already listening. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_PLUGIN\_VERSION\_MISMATCH | Installed Fastify plugin mismatched expected version. | Use a compatible version of the plugin. | [#2549](https://github.com/fastify/fastify/pull/2549) |
| FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN | Callback for a hook is not a function. | Use a function for the callback. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_VALID | Plugin must be a function or a promise. | Use a function or a promise for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_ROOT\_PLG\_BOOTED | Root plugin has already booted. | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PARENT\_PLUGIN\_BOOTED | Impossible to load plugin because the parent (mapped directly from `avvio`) | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_TIMEOUT | Plugin did not start in time. | Increase the timeout for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE | The decorator is not present in the instance. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER | The plugin being registered mixes async and callback styles. | \- | [#5141](https://github.com/fastify/fastify/pull/5141) |
| FST\_ERR\_VALIDATION | The Request failed the payload validation. | Check the request payload. | [#4824](https://github.com/fastify/fastify/pull/4824) |
| FST\_ERR\_LISTEN\_OPTIONS\_INVALID | Invalid listen options. | Check the listen options. | [#4886](https://github.com/fastify/fastify/pull/4886) |
| FST\_ERR\_ERROR\_HANDLER\_NOT\_FN | Error Handler must be a function | Provide a function to `setErrorHandler`. | [#5317](https://github.com/fastify/fastify/pull/5317) |
* [Errors](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.3.x/Reference/Errors/#error-handling-in-nodejs)
* [Errors In Fastify](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.3.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fastify-error-codes)
---
# Decorators | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Decorators[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorators "Direct link to Decorators")
------------------------------------------------------------------------------------------------------------
The decorators API customizes core Fastify objects, such as the server instance and any request and reply objects used during the HTTP request lifecycle. It can attach any type of property to core objects, e.g., functions, plain objects, or native types.
This API is _synchronous_. Defining a decoration asynchronously could result in the Fastify instance booting before the decoration completes. To register an asynchronous decoration, use the `register` API with `fastify-plugin`. See the [Plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
documentation for more details.
Decorating core objects with this API allows the underlying JavaScript engine to optimize the handling of server, request, and reply objects. This is accomplished by defining the shape of all such object instances before they are instantiated and used. As an example, the following is not recommended because it will change the shape of objects during their lifecycle:
// Bad example! Continue reading.// Attach a user property to the incoming request before the request// handler is invoked.fastify.addHook('preHandler', function (req, reply, done) { req.user = 'Bob Dylan' done()})// Use the attached user property in the request handler.fastify.get('/', function (req, reply) { reply.send(`Hello, ${req.user}`)})
The above example mutates the request object after instantiation, causing the JavaScript engine to deoptimize access. Using the decoration API avoids this deoptimization:
// Decorate request with a 'user' propertyfastify.decorateRequest('user', '')// Update our propertyfastify.addHook('preHandler', (req, reply, done) => { req.user = 'Bob Dylan' done()})// And finally access itfastify.get('/', (req, reply) => { reply.send(`Hello, ${req.user}!`)})
Keep the initial shape of a decorated field close to its future dynamic value. Initialize a decorator as `''` for strings and `null` for objects or functions. This works only with value types; reference types will throw an error during Fastify startup. See [decorateRequest](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorate-request)
and [JavaScript engine fundamentals: Shapes and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
for more information.
### Usage[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#usage "Direct link to Usage")
#### `decorate(name, value, [dependencies])`[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decoratename-value-dependencies "Direct link to decoratename-value-dependencies")
This method customizes the Fastify [server](https://fastify.dev/docs/v5.4.x/Reference/Server/)
instance.
For example, to attach a new method to the server instance:
fastify.decorate('utility', function () { // Something very useful})
Non-function values can also be attached to the server instance:
fastify.decorate('conf', { db: 'some.db', port: 3000})
To access decorated properties, use the name provided to the decoration API:
fastify.utility()console.log(fastify.conf.db)
The decorated [Fastify server](https://fastify.dev/docs/v5.4.x/Reference/Server/)
is bound to `this` in [route](https://fastify.dev/docs/v5.4.x/Reference/Routes/)
handlers:
fastify.decorate('db', new DbConnection())fastify.get('/', async function (request, reply) { // using return return { hello: await this.db.query('world') } // or // using reply.send() reply.send({ hello: await this.db.query('world') }) await reply})
The `dependencies` parameter is an optional list of decorators that the decorator being defined relies upon. This list contains the names of other decorators. In the following example, the "utility" decorator depends on the "greet" and "hi" decorators:
async function greetDecorator (fastify, opts) { fastify.decorate('greet', () => { return 'greet message' })}async function hiDecorator (fastify, opts) { fastify.decorate('hi', () => { return 'hi message' })}async function utilityDecorator (fastify, opts) { fastify.decorate('utility', () => { return `${fastify.greet()} | ${fastify.hi()}` })}fastify.register(fastifyPlugin(greetDecorator, { name: 'greet' }))fastify.register(fastifyPlugin(hiDecorator, { name: 'hi' }))fastify.register(fastifyPlugin(utilityDecorator, { dependencies: ['greet', 'hi'] }))fastify.get('/', function (req, reply) { // Response: {"hello":"greet message | hi message"} reply.send({ hello: fastify.utility() })})fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err})
Using an arrow function breaks the binding of `this` to the `FastifyInstance`.
If a dependency is not satisfied, the `decorate` method throws an exception. The dependency check occurs before the server instance boots, not during runtime.
#### `decorateReply(name, value, [dependencies])`[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decoratereplyname-value-dependencies "Direct link to decoratereplyname-value-dependencies")
This API adds new methods/properties to the core `Reply` object:
fastify.decorateReply('utility', function () { // Something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Reply` instance.
Using `decorateReply` will throw and error if used with a reference type:
// Don't do thisfastify.decorateReply('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
.
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateReply('foo') app.addHook('onRequest', async (req, reply) => { reply.foo = { bar: 42 } })}module.exports = fp(myPlugin)
See [`decorate`](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `decorateRequest(name, value, [dependencies])`[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decoraterequestname-value-dependencies "Direct link to decoraterequestname-value-dependencies")
As with [`decorateReply`](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorate-reply)
, this API adds new methods/properties to the core `Request` object:
fastify.decorateRequest('utility', function () { // something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Request` instance.
Using `decorateRequest` will emit an error if used with a reference type:
// Don't do thisfastify.decorateRequest('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
.
Example:
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateRequest('foo') app.addHook('onRequest', async (req, reply) => { req.foo = { bar: 42 } })}module.exports = fp(myPlugin)
The hook solution is more flexible and allows for more complex initialization because more logic can be added to the `onRequest` hook.
Another approach is to use the getter/setter pattern, but it requires 2 decorators:
fastify.decorateRequest('my_decorator_holder') // define the holderfastify.decorateRequest('user', { getter () { this.my_decorator_holder ??= {} // initialize the holder return this.my_decorator_holder }})fastify.get('/', async function (req, reply) { req.user.access = 'granted' // other code})
This ensures that the `user` property is always unique for each request.
See [`decorate`](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `hasDecorator(name)`[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#hasdecoratorname "Direct link to hasdecoratorname")
Used to check for the existence of a server instance decoration:
fastify.hasDecorator('utility')
#### hasRequestDecorator[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#hasrequestdecorator "Direct link to hasRequestDecorator")
Used to check for the existence of a Request decoration:
fastify.hasRequestDecorator('utility')
#### hasReplyDecorator[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#hasreplydecorator "Direct link to hasReplyDecorator")
Used to check for the existence of a Reply decoration:
fastify.hasReplyDecorator('utility')
### Decorators and Encapsulation[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorators-and-encapsulation "Direct link to Decorators and Encapsulation")
Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`) with the same name more than once in the same **encapsulated** context will throw an exception. For example, the following will throw:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine})server.get('/', (req, reply) => { reply.view('/index.html', { hello: 'world' })})// Somewhere else in our codebase, we define another// view decorator. This throws.server.decorateReply('view', function (template, args) { // Another rendering engine})server.listen({ port: 3000 })
But this will not:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine.})server.register(async function (server, opts) { // We add a view decorator to the current encapsulated // plugin. This will not throw as outside of this encapsulated // plugin view is the old one, while inside it is the new one. server.decorateReply('view', function (template, args) { // Another rendering engine }) server.get('/', (req, reply) => { reply.view('/index.page', { hello: 'world' }) })}, { prefix: '/bar' })server.listen({ port: 3000 })
### Getters and Setters[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#getters-and-setters "Direct link to Getters and Setters")
Decorators accept special "getter/setter" objects with `getter` and optional `setter` functions. This allows defining properties via decorators, for example:
fastify.decorate('foo', { getter () { return 'a getter' }})
Will define the `foo` property on the Fastify instance:
console.log(fastify.foo) // 'a getter'
### `getDecorator` API[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#getdecoratort-api "Direct link to getdecoratort-api")
Fastify's `getDecorator` API retrieves an existing decorator from the Fastify instance, `Request`, or `Reply`. If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
#### Use cases[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#use-cases "Direct link to Use cases")
**Early Plugin Dependency Validation**
`getDecorator` on Fastify instance verifies that required decorators are available at registration time.
For example:
fastify.register(async function (fastify) { const usersRepository = fastify.getDecorator('usersRepository') fastify.get('/users', async function (request, reply) { // We are sure `usersRepository` exists at runtime return usersRepository.findAll() })})
**Handling Missing Decorators**
Directly accessing a decorator may lead to unexpected behavior if it is not declared:
const user = request.user;if (user && user.isAdmin) { // Execute admin tasks.}
If `request.user` doesn't exist, then `user` will be set to `undefined`. This makes it unclear whether the user is unauthenticated or the decorator is missing.
Using `getDecorator` enforces runtime safety:
// If the decorator is missing, an explicit `FST_ERR_DEC_UNDECLARED` // error is thrown immediately.const user = request.getDecorator('user');if (user && user.isAdmin) { // Execute admin tasks.}
**Alternative to Module Augmentation**
Decorators are typically typed via module augmentation:
declare module 'fastify' { interface FastifyInstance { usersRepository: IUsersRepository } interface FastifyRequest { session: ISession } interface FastifyReply { sendSuccess: SendSuccessFn }}
This approach modifies the Fastify instance globally, which may lead to conflicts and inconsistent behavior in multi-server setups or with plugin encapsulation.
Using `getDecorator` allows to limit types scope:
serverOne.register(async function (fastify) { const usersRepository = fastify.getDecorator( 'usersRepository' ) fastify.decorateRequest('session', null) fastify.addHook('onRequest', async (req, reply) => { // Yes, the request object has a setDecorator method. // More information will be provided soon. req.setDecorator('session', { user: 'Jean' }) }) fastify.get('/me', (request, reply) => { const session = request.getDecorator('session') reply.send(session) })})serverTwo.register(async function (fastify) { const usersRepository = fastify.getDecorator( 'usersRepository' ) fastify.decorateReply('sendSuccess', function (data) { return this.send({ success: true }) }) fastify.get('/success', async (request, reply) => { const sendSuccess = reply.getDecorator('sendSuccess') await sendSuccess() })})
#### Bound functions inference[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#bound-functions-inference "Direct link to Bound functions inference")
To save time, it's common to infer function types instead of writing them manually:
function sendSuccess (this: FastifyReply) { return this.send({ success: true })}export type SendSuccess = typeof sendSuccess
However, `getDecorator` returns functions with the `this` context already **bound**, meaning the `this` parameter disappears from the function signature.
To correctly type it, you should use `OmitThisParameter` utility:
function sendSuccess (this: FastifyReply) { return this.send({ success: true })}type BoundSendSuccess = OmitThisParameterfastify.decorateReply('sendSuccess', sendSuccess)fastify.get('/success', async (request, reply) => { const sendSuccess = reply.getDecorator('sendSuccess') await sendSuccess()})
### `Request.setDecorator` Method[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#requestsetdecoratort-method "Direct link to requestsetdecoratort-method")
The `setDecorator` method provides a safe and convenient way to update the value of a `Request` decorator.
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
#### Use Cases[](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#use-cases-1 "Direct link to Use Cases")
**Runtime Safety**
A typical way to set a `Request` decorator looks like this:
fastify.decorateRequest('user', '')fastify.addHook('preHandler', async (req, reply) => { req.user = 'Bob Dylan'})
However, there is no guarantee that the decorator actually exists unless you manually check beforehand.
Additionally, typos are common, e.g. `account`, `acount`, or `accout`.
By using `setDecorator`, you are always sure that the decorator exists:
fastify.decorateRequest('user', '')fastify.addHook('preHandler', async (req, reply) => { // Throws FST_ERR_DEC_UNDECLARED if the decorator does not exist req.setDecorator('user-with-typo', 'Bob Dylan')})
* * *
**Type Safety**
If the `FastifyRequest` interface does not declare the decorator, you would typically need to use type assertions:
fastify.addHook('preHandler', async (req, reply) => { (req as typeof req & { user: string }).user = 'Bob Dylan'})
The `setDecorator` method eliminates the need for explicit type assertions while allowing type safety:
fastify.addHook('preHandler', async (req, reply) => { req.setDecorator('user', 'Bob Dylan')})
* [Decorators](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorators)
* [Usage](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#usage)
* [Decorators and Encapsulation](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#decorators-and-encapsulation)
* [Getters and Setters](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#getters-and-setters)
* [`getDecorator` API](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#getdecoratort-api)
* [`Request.setDecorator` Method](https://fastify.dev/docs/v5.4.x/Reference/Decorators/#requestsetdecoratort-method)
---
# Request | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Request/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Request[](https://fastify.dev/docs/v5.4.x/Reference/Request/#request "Direct link to Request")
------------------------------------------------------------------------------------------------
The first parameter of the handler function is `Request`.
Request is a core Fastify object containing the following fields:
* `query` - The parsed querystring, its format is specified by [`querystringParser`](https://fastify.dev/docs/v5.4.x/Reference/Server/#querystringparser)
.
* `body` - The request payload, see [Content-Type Parser](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/)
for details on what request payloads Fastify natively parses and how to support other content types.
* `params` - The params matching the URL.
* [`headers`](https://fastify.dev/docs/v5.4.x/Reference/Request/#headers)
- The headers getter and setter.
* `raw` - The incoming HTTP request from Node core.
* `server` - The Fastify server instance, scoped to the current [encapsulation context](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/)
.
* `id` - The request ID.
* `log` - The logger instance of the incoming request.
* `ip` - The IP address of the incoming request.
* `ips` - An array of the IP addresses, ordered from closest to furthest, in the `X-Forwarded-For` header of the incoming request (only when the [`trustProxy`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-trust-proxy)
option is enabled).
* `host` - The host of the incoming request (derived from `X-Forwarded-Host` header when the [`trustProxy`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-trust-proxy)
option is enabled). For HTTP/2 compatibility, it returns `:authority` if no host header exists. The host header may return an empty string if `requireHostHeader` is `false`, not provided with HTTP/1.0, or removed by schema validation.
* `hostname` - The hostname derived from the `host` property of the incoming request.
* `port` - The port from the `host` property, which may refer to the port the server is listening on.
* `protocol` - The protocol of the incoming request (`https` or `http`).
* `method` - The method of the incoming request.
* `url` - The URL of the incoming request.
* `originalUrl` - Similar to `url`, allows access to the original `url` in case of internal re-routing.
* `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
* `socket` - The underlying connection of the incoming request.
* `context` - Deprecated, use `request.routeOptions.config` instead. A Fastify internal object. Do not use or modify it directly. It is useful to access one special key:
* `context.config` - The route [`config`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-config)
object.
* `routeOptions` - The route [`option`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-options)
object.
* `bodyLimit` - Either server limit or route limit.
* `config` - The [`config`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-config)
object for this route.
* `method` - The HTTP method for the route.
* `url` - The path of the URL to match this route.
* `handler` - The handler for this route.
* `attachValidation` - Attach `validationError` to request (if there is a schema defined).
* `logLevel` - Log level defined for this route.
* `schema` - The JSON schemas definition for this route.
* `version` - A semver compatible string that defines the version of the endpoint.
* `exposeHeadRoute` - Creates a sibling HEAD route for any GET routes.
* `prefixTrailingSlash` - String used to determine how to handle passing `/` as a route with a prefix.
* [.getValidationFunction(schema | httpPart)](https://fastify.dev/docs/v5.4.x/Reference/Request/#getvalidationfunction)
- Returns a validation function for the specified schema or HTTP part, if set or cached.
* [.compileValidationSchema(schema, \[httpPart\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#compilevalidationschema)
- Compiles the specified schema and returns a validation function using the default (or customized) `ValidationCompiler`. The optional `httpPart` is forwarded to the `ValidationCompiler` if provided, defaults to `null`.
* [.validateInput(data, schema | httpPart, \[httpPart\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#validate)
- Validates the input using the specified schema and returns the serialized payload. If `httpPart` is provided, the function uses the serializer for that HTTP Status Code. Defaults to `null`.
### Headers[](https://fastify.dev/docs/v5.4.x/Reference/Request/#headers "Direct link to Headers")
The `request.headers` is a getter that returns an object with the headers of the incoming request. Set custom headers as follows:
request.headers = { 'foo': 'bar', 'baz': 'qux'}
This operation adds new values to the request headers, accessible via `request.headers.bar`. Standard request headers remain accessible via `request.raw.headers`.
For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added to headers on `not found` routes.
> ℹ️ Note: Schema validation may mutate the `request.headers` and `request.raw.headers` objects, causing the headers to become empty.
fastify.post('/:params', options, function (request, reply) { console.log(request.body) console.log(request.query) console.log(request.params) console.log(request.headers) console.log(request.raw) console.log(request.server) console.log(request.id) console.log(request.ip) console.log(request.ips) console.log(request.host) console.log(request.hostname) console.log(request.port) console.log(request.protocol) console.log(request.url) console.log(request.routeOptions.method) console.log(request.routeOptions.bodyLimit) console.log(request.routeOptions.method) console.log(request.routeOptions.url) console.log(request.routeOptions.attachValidation) console.log(request.routeOptions.logLevel) console.log(request.routeOptions.version) console.log(request.routeOptions.exposeHeadRoute) console.log(request.routeOptions.prefixTrailingSlash) console.log(request.routeOptions.logLevel) request.log.info('some info')})
### .getValidationFunction(schema | httpPart)[](https://fastify.dev/docs/v5.4.x/Reference/Request/#getvalidationfunctionschema--httppart "Direct link to .getValidationFunction(schema | httpPart)")
By calling this function with a provided `schema` or `httpPart`, it returns a `validation` function to validate diverse inputs. It returns `undefined` if no serialization function is found using the provided inputs.
This function has an `errors` property. Errors encountered during the last validation are assigned to `errors`.
const validate = request .getValidationFunction({ type: 'object', properties: { foo: { type: 'string' } } })console.log(validate({ foo: 'bar' })) // trueconsole.log(validate.errors) // null// orconst validate = request .getValidationFunction('body')console.log(validate({ foo: 0.5 })) // falseconsole.log(validate.errors) // validation errors
See [.compileValidationSchema(schema, \[httpStatus\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#compileValidationSchema)
for more information on compiling validation schemas.
### .compileValidationSchema(schema, \[httpPart\])[](https://fastify.dev/docs/v5.4.x/Reference/Request/#compilevalidationschemaschema-httppart "Direct link to .compileValidationSchema(schema, [httpPart])")
This function compiles a validation schema and returns a function to validate data. The returned function (a.k.a. _validation function_) is compiled using the provided [`SchemaController#ValidationCompiler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#schema-controller)
. A `WeakMap` is used to cache this, reducing compilation calls.
The optional parameter `httpPart`, if provided, is forwarded to the `ValidationCompiler`, allowing it to compile the validation function if a custom `ValidationCompiler` is provided for the route.
This function has an `errors` property. Errors encountered during the last validation are assigned to `errors`.
const validate = request .compileValidationSchema({ type: 'object', properties: { foo: { type: 'string' } } })console.log(validate({ foo: 'bar' })) // trueconsole.log(validate.errors) // null// orconst validate = request .compileValidationSchema({ type: 'object', properties: { foo: { type: 'string' } } }, 200)console.log(validate({ hello: 'world' })) // falseconsole.log(validate.errors) // validation errors
Be careful when using this function, as it caches compiled validation functions based on the provided schema. If schemas are mutated or changed, the validation functions will not detect the alterations and will reuse the previously compiled validation function, as the cache is based on the schema's reference.
If schema properties need to be changed, create a new schema object to benefit from the cache mechanism.
Using the following schema as an example:
const schema1 = { type: 'object', properties: { foo: { type: 'string' } }}
_Not_
const validate = request.compileValidationSchema(schema1)// Later on...schema1.properties.foo.type. = 'integer'const newValidate = request.compileValidationSchema(schema1)console.log(newValidate === validate) // true
_Instead_
const validate = request.compileValidationSchema(schema1)// Later on...const newSchema = Object.assign({}, schema1)newSchema.properties.foo.type = 'integer'const newValidate = request.compileValidationSchema(newSchema)console.log(newValidate === validate) // false
### .validateInput(data, \[schema | httpStatus\], \[httpStatus\])[](https://fastify.dev/docs/v5.4.x/Reference/Request/#validateinputdata-schema--httpstatus-httpstatus "Direct link to .validateInput(data, [schema | httpStatus], [httpStatus])")
This function validates the input based on the provided schema or HTTP part. If both are provided, the `httpPart` parameter takes precedence.
If no validation function exists for a given `schema`, a new validation function will be compiled, forwarding the `httpPart` if provided.
request .validateInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }) // true// orrequest .validateInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }, 'body') // true// orrequest .validateInput({ hello: 'world'}, 'query') // false
See [.compileValidationSchema(schema, \[httpStatus\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#compileValidationSchema)
for more information on compiling validation schemas.
* [Request](https://fastify.dev/docs/v5.4.x/Reference/Request/#request)
* [Headers](https://fastify.dev/docs/v5.4.x/Reference/Request/#headers)
* [.getValidationFunction(schema | httpPart)](https://fastify.dev/docs/v5.4.x/Reference/Request/#getvalidationfunctionschema--httppart)
* [.compileValidationSchema(schema, \[httpPart\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#compilevalidationschemaschema-httppart)
* [.validateInput(data, \[schema | httpStatus\], \[httpStatus\])](https://fastify.dev/docs/v5.4.x/Reference/Request/#validateinputdata-schema--httpstatus-httpstatus)
---
# Decorators | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Decorators/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Decorators[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorators "Direct link to Decorators")
------------------------------------------------------------------------------------------------------------
The decorators API customizes core Fastify objects, such as the server instance and any request and reply objects used during the HTTP request lifecycle. It can attach any type of property to core objects, e.g., functions, plain objects, or native types.
This API is _synchronous_. Defining a decoration asynchronously could result in the Fastify instance booting before the decoration completes. To register an asynchronous decoration, use the `register` API with `fastify-plugin`. See the [Plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
documentation for more details.
Decorating core objects with this API allows the underlying JavaScript engine to optimize the handling of server, request, and reply objects. This is accomplished by defining the shape of all such object instances before they are instantiated and used. As an example, the following is not recommended because it will change the shape of objects during their lifecycle:
// Bad example! Continue reading.// Attach a user property to the incoming request before the request// handler is invoked.fastify.addHook('preHandler', function (req, reply, done) { req.user = 'Bob Dylan' done()})// Use the attached user property in the request handler.fastify.get('/', function (req, reply) { reply.send(`Hello, ${req.user}`)})
The above example mutates the request object after instantiation, causing the JavaScript engine to deoptimize access. Using the decoration API avoids this deoptimization:
// Decorate request with a 'user' propertyfastify.decorateRequest('user', '')// Update our propertyfastify.addHook('preHandler', (req, reply, done) => { req.user = 'Bob Dylan' done()})// And finally access itfastify.get('/', (req, reply) => { reply.send(`Hello, ${req.user}!`)})
Keep the initial shape of a decorated field close to its future dynamic value. Initialize a decorator as `''` for strings and `null` for objects or functions. This works only with value types; reference types will throw an error during Fastify startup. See [decorateRequest](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorate-request)
and [JavaScript engine fundamentals: Shapes and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
for more information.
### Usage[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#usage "Direct link to Usage")
#### `decorate(name, value, [dependencies])`[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decoratename-value-dependencies "Direct link to decoratename-value-dependencies")
This method customizes the Fastify [server](https://fastify.dev/docs/v5.3.x/Reference/Server/)
instance.
For example, to attach a new method to the server instance:
fastify.decorate('utility', function () { // Something very useful})
Non-function values can also be attached to the server instance:
fastify.decorate('conf', { db: 'some.db', port: 3000})
To access decorated properties, use the name provided to the decoration API:
fastify.utility()console.log(fastify.conf.db)
The decorated [Fastify server](https://fastify.dev/docs/v5.3.x/Reference/Server/)
is bound to `this` in [route](https://fastify.dev/docs/v5.3.x/Reference/Routes/)
handlers:
fastify.decorate('db', new DbConnection())fastify.get('/', async function (request, reply) { // using return return { hello: await this.db.query('world') } // or // using reply.send() reply.send({ hello: await this.db.query('world') }) await reply})
The `dependencies` parameter is an optional list of decorators that the decorator being defined relies upon. This list contains the names of other decorators. In the following example, the "utility" decorator depends on the "greet" and "hi" decorators:
async function greetDecorator (fastify, opts) { fastify.decorate('greet', () => { return 'greet message' })}async function hiDecorator (fastify, opts) { fastify.decorate('hi', () => { return 'hi message' })}async function utilityDecorator (fastify, opts) { fastify.decorate('utility', () => { return `${fastify.greet()} | ${fastify.hi()}` })}fastify.register(fastifyPlugin(greetDecorator, { name: 'greet' }))fastify.register(fastifyPlugin(hiDecorator, { name: 'hi' }))fastify.register(fastifyPlugin(utilityDecorator, { dependencies: ['greet', 'hi'] }))fastify.get('/', function (req, reply) { // Response: {"hello":"greet message | hi message"} reply.send({ hello: fastify.utility() })})fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err})
Using an arrow function breaks the binding of `this` to the `FastifyInstance`.
If a dependency is not satisfied, the `decorate` method throws an exception. The dependency check occurs before the server instance boots, not during runtime.
#### `decorateReply(name, value, [dependencies])`[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decoratereplyname-value-dependencies "Direct link to decoratereplyname-value-dependencies")
This API adds new methods/properties to the core `Reply` object:
fastify.decorateReply('utility', function () { // Something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Reply` instance.
Using `decorateReply` will throw and error if used with a reference type:
// Don't do thisfastify.decorateReply('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
.
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateReply('foo') app.addHook('onRequest', async (req, reply) => { reply.foo = { bar: 42 } })}module.exports = fp(myPlugin)
See [`decorate`](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `decorateRequest(name, value, [dependencies])`[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decoraterequestname-value-dependencies "Direct link to decoraterequestname-value-dependencies")
As with [`decorateReply`](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorate-reply)
, this API adds new methods/properties to the core `Request` object:
fastify.decorateRequest('utility', function () { // something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Request` instance.
Using `decorateRequest` will emit an error if used with a reference type:
// Don't do thisfastify.decorateRequest('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
.
Example:
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateRequest('foo') app.addHook('onRequest', async (req, reply) => { req.foo = { bar: 42 } })}module.exports = fp(myPlugin)
The hook solution is more flexible and allows for more complex initialization because more logic can be added to the `onRequest` hook.
Another approach is to use the getter/setter pattern, but it requires 2 decorators:
fastify.decorateRequest('my_decorator_holder') // define the holderfastify.decorateRequest('user', { getter () { this.my_decorator_holder ??= {} // initialize the holder return this.my_decorator_holder }})fastify.get('/', async function (req, reply) { req.user.access = 'granted' // other code})
This ensures that the `user` property is always unique for each request.
See [`decorate`](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `hasDecorator(name)`[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#hasdecoratorname "Direct link to hasdecoratorname")
Used to check for the existence of a server instance decoration:
fastify.hasDecorator('utility')
#### hasRequestDecorator[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#hasrequestdecorator "Direct link to hasRequestDecorator")
Used to check for the existence of a Request decoration:
fastify.hasRequestDecorator('utility')
#### hasReplyDecorator[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#hasreplydecorator "Direct link to hasReplyDecorator")
Used to check for the existence of a Reply decoration:
fastify.hasReplyDecorator('utility')
### Decorators and Encapsulation[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorators-and-encapsulation "Direct link to Decorators and Encapsulation")
Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`) with the same name more than once in the same **encapsulated** context will throw an exception. For example, the following will throw:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine})server.get('/', (req, reply) => { reply.view('/index.html', { hello: 'world' })})// Somewhere else in our codebase, we define another// view decorator. This throws.server.decorateReply('view', function (template, args) { // Another rendering engine})server.listen({ port: 3000 })
But this will not:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine.})server.register(async function (server, opts) { // We add a view decorator to the current encapsulated // plugin. This will not throw as outside of this encapsulated // plugin view is the old one, while inside it is the new one. server.decorateReply('view', function (template, args) { // Another rendering engine }) server.get('/', (req, reply) => { reply.view('/index.page', { hello: 'world' }) })}, { prefix: '/bar' })server.listen({ port: 3000 })
### Getters and Setters[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#getters-and-setters "Direct link to Getters and Setters")
Decorators accept special "getter/setter" objects with `getter` and optional `setter` functions. This allows defining properties via decorators, for example:
fastify.decorate('foo', { getter () { return 'a getter' }})
Will define the `foo` property on the Fastify instance:
console.log(fastify.foo) // 'a getter'
### `getDecorator` API[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#getdecoratort-api "Direct link to getdecoratort-api")
Fastify's `getDecorator` API retrieves an existing decorator from the Fastify instance, `Request`, or `Reply`. If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
#### Use cases[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#use-cases "Direct link to Use cases")
**Early Plugin Dependency Validation**
`getDecorator` on Fastify instance verifies that required decorators are available at registration time.
For example:
fastify.register(async function (fastify) { const usersRepository = fastify.getDecorator('usersRepository') fastify.get('/users', async function (request, reply) { // We are sure `usersRepository` exists at runtime return usersRepository.findAll() })})
**Handling Missing Decorators**
Directly accessing a decorator may lead to unexpected behavior if it is not declared:
const user = request.user;if (user && user.isAdmin) { // Execute admin tasks.}
If `request.user` doesn't exist, then `user` will be set to `undefined`. This makes it unclear whether the user is unauthenticated or the decorator is missing.
Using `getDecorator` enforces runtime safety:
// If the decorator is missing, an explicit `FST_ERR_DEC_UNDECLARED` // error is thrown immediately.const user = request.getDecorator('user');if (user && user.isAdmin) { // Execute admin tasks.}
**Alternative to Module Augmentation**
Decorators are typically typed via module augmentation:
declare module 'fastify' { interface FastifyInstance { usersRepository: IUsersRepository } interface FastifyRequest { session: ISession } interface FastifyReply { sendSuccess: SendSuccessFn }}
This approach modifies the Fastify instance globally, which may lead to conflicts and inconsistent behavior in multi-server setups or with plugin encapsulation.
Using `getDecorator` allows to limit types scope:
serverOne.register(async function (fastify) { const usersRepository = fastify.getDecorator( 'usersRepository' ) fastify.decorateRequest('session', null) fastify.addHook('onRequest', async (req, reply) => { // Yes, the request object has a setDecorator method. // More information will be provided soon. req.setDecorator('session', { user: 'Jean' }) }) fastify.get('/me', (request, reply) => { const session = request.getDecorator('session') reply.send(session) })})serverTwo.register(async function (fastify) { const usersRepository = fastify.getDecorator( 'usersRepository' ) fastify.decorateReply('sendSuccess', function (data) { return this.send({ success: true }) }) fastify.get('/success', async (request, reply) => { const sendSuccess = reply.getDecorator('sendSuccess') await sendSuccess() })})
#### Bound functions inference[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#bound-functions-inference "Direct link to Bound functions inference")
To save time, it's common to infer function types instead of writing them manually:
function sendSuccess (this: FastifyReply) { return this.send({ success: true })}export type SendSuccess = typeof sendSuccess
However, `getDecorator` returns functions with the `this` context already **bound**, meaning the `this` parameter disappears from the function signature.
To correctly type it, you should use `OmitThisParameter` utility:
function sendSuccess (this: FastifyReply) { return this.send({ success: true })}type BoundSendSuccess = OmitThisParameterfastify.decorateReply('sendSuccess', sendSuccess)fastify.get('/success', async (request, reply) => { const sendSuccess = reply.getDecorator('sendSuccess') await sendSuccess()})
### `Request.setDecorator` Method[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#requestsetdecoratort-method "Direct link to requestsetdecoratort-method")
The `setDecorator` method provides a safe and convenient way to update the value of a `Request` decorator.
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
#### Use Cases[](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#use-cases-1 "Direct link to Use Cases")
**Runtime Safety**
A typical way to set a `Request` decorator looks like this:
fastify.decorateRequest('user', '')fastify.addHook('preHandler', async (req, reply) => { req.user = 'Bob Dylan'})
However, there is no guarantee that the decorator actually exists unless you manually check beforehand.
Additionally, typos are common, e.g. `account`, `acount`, or `accout`.
By using `setDecorator`, you are always sure that the decorator exists:
fastify.decorateRequest('user', '')fastify.addHook('preHandler', async (req, reply) => { // Throws FST_ERR_DEC_UNDECLARED if the decorator does not exist req.setDecorator('user-with-typo', 'Bob Dylan')})
* * *
**Type Safety**
If the `FastifyRequest` interface does not declare the decorator, you would typically need to use type assertions:
fastify.addHook('preHandler', async (req, reply) => { (req as typeof req & { user: string }).user = 'Bob Dylan'})
The `setDecorator` method eliminates the need for explicit type assertions while allowing type safety:
fastify.addHook('preHandler', async (req, reply) => { req.setDecorator('user', 'Bob Dylan')})
* [Decorators](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorators)
* [Usage](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#usage)
* [Decorators and Encapsulation](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#decorators-and-encapsulation)
* [Getters and Setters](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#getters-and-setters)
* [`getDecorator` API](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#getdecoratort-api)
* [`Request.setDecorator` Method](https://fastify.dev/docs/v5.3.x/Reference/Decorators/#requestsetdecoratort-method)
---
# Logging | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Logging/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Logging/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Logging[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#logging "Direct link to Logging")
------------------------------------------------------------------------------------------------
### Enable Logging[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#enable-logging "Direct link to Enable Logging")
Logging is disabled by default. Enable it by passing `{ logger: true }` or `{ logger: { level: 'info' } }` when creating a Fastify instance. Note that if the logger is disabled, it cannot be enabled at runtime. [abstract-logging](https://www.npmjs.com/package/abstract-logging)
is used for this purpose.
As Fastify is focused on performance, it uses [pino](https://github.com/pinojs/pino)
as its logger, with the default log level set to `'info'` when enabled.
#### Basic logging setup[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#basic-logging-setup "Direct link to Basic logging setup")
Enabling the production JSON logger:
const fastify = require('fastify')({ logger: true})
#### Environment-Specific Configuration[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#environment-specific-configuration "Direct link to Environment-Specific Configuration")
Enabling the logger with appropriate configuration for local development, production, and test environments requires more configuration:
const envToLogger = { development: { transport: { target: 'pino-pretty', options: { translateTime: 'HH:MM:ss Z', ignore: 'pid,hostname', }, }, }, production: true, test: false,}const fastify = require('fastify')({ logger: envToLogger[environment] ?? true // defaults to true if no entry matches in the map})
⚠️ `pino-pretty` needs to be installed as a dev dependency. It is not included by default for performance reasons.
### Usage[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#usage "Direct link to Usage")
The logger can be used in route handlers as follows:
fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
Trigger new logs outside route handlers using the Pino instance from the Fastify instance:
fastify.log.info('Something important happened!');
#### Passing Logger Options[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#passing-logger-options "Direct link to Passing Logger Options")
To pass options to the logger, provide them to Fastify. See the [Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options)
for available options. To specify a file destination, use:
const fastify = require('fastify')({ logger: { level: 'info', file: '/path/to/file' // Will use pino.destination() }})fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
To pass a custom stream to the Pino instance, add a `stream` field to the logger object:
const split = require('split2')const stream = split(JSON.parse)const fastify = require('fastify')({ logger: { level: 'info', stream: stream }})
### Advanced Logger Configuration[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#advanced-logger-configuration "Direct link to Advanced Logger Configuration")
#### Request ID Tracking[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#request-id-tracking "Direct link to Request ID Tracking")
By default, Fastify adds an ID to every request for easier tracking. If the `requestIdHeader` option is set and the corresponding header is present, its value is used; otherwise, a new incremental ID is generated. See Fastify Factory [`requestIdHeader`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-request-id-header)
and Fastify Factory [`genReqId`](https://fastify.dev/docs/v5.3.x/Reference/Server/#genreqid)
for customization options.
#### Serializers[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#serializers "Direct link to Serializers")
The default logger uses standard serializers for objects with `req`, `res`, and `err` properties. The `req` object is the Fastify [`Request`](https://fastify.dev/docs/v5.3.x/Reference/Request/)
object, and the `res` object is the Fastify [`Reply`](https://fastify.dev/docs/v5.3.x/Reference/Reply/)
object. This behavior can be customized with custom serializers.
const fastify = require('fastify')({ logger: { serializers: { req (request) { return { url: request.url } } } }})
For example, the response payload and headers could be logged using the approach below (not recommended):
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode } }, req (request) { return { method: request.method, url: request.url, path: request.routeOptions.url, parameters: request.params, // Including headers in the log could violate privacy laws, // e.g., GDPR. Use the "redact" option to remove sensitive // fields. It could also leak authentication data in the logs. headers: request.headers }; } } }});
> 🛈 Note: In some cases, the [`Reply`](https://fastify.dev/docs/v5.3.x/Reference/Reply/)
> object passed to the `res` serializer cannot be fully constructed. When writing a custom `res` serializer, check for the existence of any properties on `reply` aside from `statusCode`, which is always present. For example, verify the existence of `getHeaders` before calling it:
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode, headers: typeof reply.getHeaders === 'function' ? reply.getHeaders() : {} } }, } }});
> 🛈 Note: The body cannot be serialized inside a `req` method because the request is serialized when the child logger is created. At that time, the body is not yet parsed.
See the following approach to log `req.body`:
app.addHook('preHandler', function (req, reply, done) { if (req.body) { req.log.info({ body: req.body }, 'parsed body') } done()})
> 🛈 Note: Ensure serializers never throw errors, as this can cause the Node process to exit. See the [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers)
> for more information.
_Any logger other than Pino will ignore this option._
### Using Custom Loggers[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#using-custom-loggers "Direct link to Using Custom Loggers")
A custom logger instance can be supplied by passing it as `loggerInstance`. The logger must conform to the Pino interface, with methods: `info`, `error`, `debug`, `fatal`, `warn`, `trace`, `silent`, `child`, and a string property `level`.
Example:
const log = require('pino')({ level: 'info' })const fastify = require('fastify')({ loggerInstance: log })log.info('does not have request information')fastify.get('/', function (request, reply) { request.log.info('includes request information, but is the same logger instance as `log`') reply.send({ hello: 'world' })})
_The logger instance for the current request is available in every part of the [lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/)
._
### Log Redaction[](https://fastify.dev/docs/v5.3.x/Reference/Logging/#log-redaction "Direct link to Log Redaction")
[Pino](https://getpino.io/)
supports low-overhead log redaction for obscuring values of specific properties in recorded logs. For example, log all HTTP headers except the `Authorization` header for security:
const fastify = Fastify({ logger: { stream: stream, redact: ['req.headers.authorization'], level: 'info', serializers: { req (request) { return { method: request.method, url: request.url, headers: request.headers, host: request.host, remoteAddress: request.ip, remotePort: request.socket.remotePort } } } }})
See [https://getpino.io/#/docs/redaction](https://getpino.io/#/docs/redaction)
for more details.
* [Logging](https://fastify.dev/docs/v5.3.x/Reference/Logging/#logging)
* [Enable Logging](https://fastify.dev/docs/v5.3.x/Reference/Logging/#enable-logging)
* [Usage](https://fastify.dev/docs/v5.3.x/Reference/Logging/#usage)
* [Advanced Logger Configuration](https://fastify.dev/docs/v5.3.x/Reference/Logging/#advanced-logger-configuration)
* [Using Custom Loggers](https://fastify.dev/docs/v5.3.x/Reference/Logging/#using-custom-loggers)
* [Log Redaction](https://fastify.dev/docs/v5.3.x/Reference/Logging/#log-redaction)
---
# Middleware | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Middleware/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Middleware[](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#middleware "Direct link to Middleware")
------------------------------------------------------------------------------------------------------------
Starting with Fastify v3.0.0, middleware is not supported out of the box and requires an external plugin such as [`@fastify/express`](https://github.com/fastify/fastify-express)
or [`@fastify/middie`](https://github.com/fastify/middie)
.
An example of registering the [`@fastify/express`](https://github.com/fastify/fastify-express)
plugin to `use` Express middleware:
await fastify.register(require('@fastify/express'))fastify.use(require('cors')())fastify.use(require('dns-prefetch-control')())fastify.use(require('frameguard')())fastify.use(require('hsts')())fastify.use(require('ienoopen')())fastify.use(require('x-xss-protection')())
[`@fastify/middie`](https://github.com/fastify/middie)
can also be used, which provides support for simple Express-style middleware with improved performance:
await fastify.register(require('@fastify/middie'))fastify.use(require('cors')())
Middleware can be encapsulated, allowing control over where it runs using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.3.x/Guides/Plugins-Guide/)
.
Fastify middleware does not expose the `send` method or other methods specific to the Fastify [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply)
instance. This is because Fastify wraps the incoming `req` and `res` Node instances using the [Request](https://fastify.dev/docs/v5.3.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply)
objects internally, but this is done after the middleware phase. To create middleware, use the Node `req` and `res` instances. Alternatively, use the `preHandler` hook that already has the Fastify [Request](https://fastify.dev/docs/v5.3.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply)
instances. For more information, see [Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#hooks)
.
#### Restrict middleware execution to certain paths[](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#restrict-middleware-execution-to-certain-paths "Direct link to Restrict middleware execution to certain paths")
To run middleware under certain paths, pass the path as the first parameter to `use`.
> 🛈 Note: This does not support routes with parameters (e.g. `/user/:id/comments`) and wildcards are not supported in multiple paths.
const path = require('node:path')const serveStatic = require('serve-static')// Single pathfastify.use('/css', serveStatic(path.join(__dirname, '/assets')))// Wildcard pathfastify.use('/css/(.*)', serveStatic(path.join(__dirname, '/assets')))// Multiple pathsfastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
### Alternatives[](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#alternatives "Direct link to Alternatives")
Fastify offers alternatives to commonly used middleware, such as [`@fastify/helmet`](https://github.com/fastify/fastify-helmet)
for [`helmet`](https://github.com/helmetjs/helmet)
, [`@fastify/cors`](https://github.com/fastify/fastify-cors)
for [`cors`](https://github.com/expressjs/cors)
, and [`@fastify/static`](https://github.com/fastify/fastify-static)
for [`serve-static`](https://github.com/expressjs/serve-static)
.
* [Middleware](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#middleware)
* [Alternatives](https://fastify.dev/docs/v5.3.x/Reference/Middleware/#alternatives)
---
# Technical Principles | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Principles/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Principles/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Every decision in the Fastify framework and its official plugins is guided by the following technical principles:
1. “Zero” overhead in production
2. “Good” developer experience
3. Works great for small & big projects alike
4. Easy to migrate to microservices (or even serverless) and back
5. Security & data validation
6. If something could be a plugin, it likely should be
7. Easily testable
8. Do not monkeypatch core
9. Semantic versioning & Long Term Support
10. Specification adherence
"Zero" Overhead in Production[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#zero-overhead-in-production "Direct link to "Zero" Overhead in Production")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to implement features with minimal overhead. This is achieved by using fast algorithms, data structures, and JavaScript-specific features.
Since JavaScript does not offer zero-overhead data structures, this principle can conflict with providing a great developer experience and additional features, as these usually incur some overhead.
"Good" Developer Experience[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#good-developer-experience "Direct link to "Good" Developer Experience")
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to provide the best developer experience at its performance point. It offers a great out-of-the-box experience that is flexible enough to adapt to various situations.
For example, binary addons are forbidden because most JavaScript developers do not have access to a compiler.
Works great for small and big projects alike[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#works-great-for-small-and-big-projects-alike "Direct link to Works great for small and big projects alike")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Most applications start small and become more complex over time. Fastify aims to grow with this complexity, providing advanced features to structure codebases.
Easy to migrate to microservices (or even serverless) and back[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back "Direct link to Easy to migrate to microservices (or even serverless) and back")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Route deployment should not matter. The framework should "just work".
Security and Data Validation[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#security-and-data-validation "Direct link to Security and Data Validation")
------------------------------------------------------------------------------------------------------------------------------------------------------------------
A web framework is the first point of contact with untrusted data and must act as the first line of defense for the system.
If something could be a plugin, it likely should[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should "Direct link to If something could be a plugin, it likely should")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Recognizing the infinite use cases for an HTTP framework, catering to all in a single module would make the codebase unmaintainable. Therefore, hooks and options are provided to customize the framework as needed.
Easily testable[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#easily-testable "Direct link to Easily testable")
---------------------------------------------------------------------------------------------------------------------------
Testing Fastify applications should be a first-class concern.
Do not monkeypatch core[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#do-not-monkeypatch-core "Direct link to Do not monkeypatch core")
---------------------------------------------------------------------------------------------------------------------------------------------------
Monkeypatching Node.js APIs or installing globals that alter the runtime makes building modular applications harder and limits Fastify's use cases. Other frameworks do this; Fastify does not.
Semantic Versioning and Long Term Support[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#semantic-versioning-and-long-term-support "Direct link to Semantic Versioning and Long Term Support")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
A clear [Long Term Support strategy is provided](https://fastify.dev/docs/v5.3.x/Reference/LTS/)
to inform developers when to upgrade.
Specification adherence[](https://fastify.dev/docs/v5.3.x/Reference/Principles/#specification-adherence "Direct link to Specification adherence")
---------------------------------------------------------------------------------------------------------------------------------------------------
In doubt, we chose the strict behavior as defined by the relevant Specifications.
* ["Zero" Overhead in Production](https://fastify.dev/docs/v5.3.x/Reference/Principles/#zero-overhead-in-production)
* ["Good" Developer Experience](https://fastify.dev/docs/v5.3.x/Reference/Principles/#good-developer-experience)
* [Works great for small and big projects alike](https://fastify.dev/docs/v5.3.x/Reference/Principles/#works-great-for-small-and-big-projects-alike)
* [Easy to migrate to microservices (or even serverless) and back](https://fastify.dev/docs/v5.3.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back)
* [Security and Data Validation](https://fastify.dev/docs/v5.3.x/Reference/Principles/#security-and-data-validation)
* [If something could be a plugin, it likely should](https://fastify.dev/docs/v5.3.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should)
* [Easily testable](https://fastify.dev/docs/v5.3.x/Reference/Principles/#easily-testable)
* [Do not monkeypatch core](https://fastify.dev/docs/v5.3.x/Reference/Principles/#do-not-monkeypatch-core)
* [Semantic Versioning and Long Term Support](https://fastify.dev/docs/v5.3.x/Reference/Principles/#semantic-versioning-and-long-term-support)
* [Specification adherence](https://fastify.dev/docs/v5.3.x/Reference/Principles/#specification-adherence)
---
# Plugins | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Plugins/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Plugins[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#plugins "Direct link to Plugins")
------------------------------------------------------------------------------------------------
Fastify can be extended with plugins, which can be a set of routes, a server [decorator](https://fastify.dev/docs/v5.3.x/Reference/Decorators/)
, or other functionality. Use the `register` API to add one or more plugins.
By default, `register` creates a _new scope_, meaning changes to the Fastify instance (via `decorate`) will not affect the current context ancestors, only its descendants. This feature enables plugin _encapsulation_ and _inheritance_, creating a _directed acyclic graph_ (DAG) and avoiding cross-dependency issues.
The [Getting Started](https://fastify.dev/docs/v5.3.x/Guides/Getting-Started/#your-first-plugin)
guide includes an example of using this API:
fastify.register(plugin, [options])
### Plugin Options[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#plugin-options "Direct link to Plugin Options")
The optional `options` parameter for `fastify.register` supports a predefined set of options that Fastify itself will use, except when the plugin has been wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin)
. This options object will also be passed to the plugin upon invocation, regardless of whether or not the plugin has been wrapped. The currently supported list of Fastify specific options is:
* [`logLevel`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-level)
* [`logSerializers`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-serializer)
* [`prefix`](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#route-prefixing-option)
These options will be ignored when used with fastify-plugin.
To avoid collisions, a plugin should consider namespacing its options. For example, a plugin `foo` might be registered like so:
fastify.register(require('fastify-foo'), { prefix: '/foo', foo: { fooOption1: 'value', fooOption2: 'value' }})
If collisions are not a concern, the plugin may accept the options object as-is:
fastify.register(require('fastify-foo'), { prefix: '/foo', fooOption1: 'value', fooOption2: 'value'})
The `options` parameter can also be a `Function` evaluated at plugin registration, providing access to the Fastify instance via the first argument:
const fp = require('fastify-plugin')fastify.register(fp((fastify, opts, done) => { fastify.decorate('foo_bar', { hello: 'world' }) done()}))// The opts argument of fastify-foo will be { hello: 'world' }fastify.register(require('fastify-foo'), parent => parent.foo_bar)
The Fastify instance passed to the function is the latest state of the **external Fastify instance** the plugin was declared on, allowing access to variables injected via [`decorate`](https://fastify.dev/docs/v5.3.x/Reference/Decorators/)
by preceding plugins according to the **order of registration**. This is useful if a plugin depends on changes made to the Fastify instance by a preceding plugin, such as utilizing an existing database connection.
Keep in mind that the Fastify instance passed to the function is the same as the one passed into the plugin, a copy of the external Fastify instance rather than a reference. Any usage of the instance will behave the same as it would if called within the plugin's function. For example, if `decorate` is called, the decorated variables will be available within the plugin's function unless it was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
.
#### Route Prefixing option[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#route-prefixing-option "Direct link to Route Prefixing option")
If an option with the key `prefix` and a `string` value is passed, Fastify will use it to prefix all the routes inside the register. For more info, check [here](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing)
.
Be aware that if routes are wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
, this option will not work (see the [workaround](https://fastify.dev/docs/v5.3.x/Reference/Routes/#fastify-plugin)
).
#### Error handling[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#error-handling "Direct link to Error handling")
Error handling is done by [avvio](https://github.com/mcollina/avvio#error-handling)
.
As a general rule, handle errors in the next `after` or `ready` block, otherwise they will be caught inside the `listen` callback.
fastify.register(require('my-plugin'))// `after` will be executed once// the previous declared `register` has finishedfastify.after(err => console.log(err))// `ready` will be executed once all the registers declared// have finished their executionfastify.ready(err => console.log(err))// `listen` is a special ready,// so it behaves in the same wayfastify.listen({ port: 3000 }, (err, address) => { if (err) console.log(err)})
### async/await[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#asyncawait "Direct link to async/await")
_async/await_ is supported by `after`, `ready`, and `listen`, as well as `fastify` being a Thenable.
await fastify.register(require('my-plugin'))await fastify.after()await fastify.ready()await fastify.listen({ port: 3000 })
Using `await` when registering a plugin loads the plugin and its dependencies, "finalizing" the encapsulation process. Any mutations to the plugin after it and its dependencies have been loaded will not be reflected in the parent instance.
#### ESM support[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#esm-support "Direct link to ESM support")
ESM is supported from [Node.js `v13.3.0`](https://nodejs.org/api/esm.html)
and above.
// main.mjsimport Fastify from 'fastify'const fastify = Fastify()fastify.register(import('./plugin.mjs'))fastify.listen({ port: 3000 }, console.log)// plugin.mjsasync function plugin (fastify, opts) { fastify.get('/', async (req, reply) => { return { hello: 'world' } })}export default plugin
### Create a plugin[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#create-a-plugin "Direct link to Create a plugin")
Creating a plugin is easy. Create a function that takes three parameters: the `fastify` instance, an `options` object, and the `done` callback.
Example:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) done()}
`register` can also be used inside another `register`:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) fastify.register(require('./other-plugin')) done()}
Remember, `register` always creates a new Fastify scope. If this is not needed, read the following section.
### Handle the scope[](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#handle-the-scope "Direct link to Handle the scope")
If `register` is used only to extend server functionality with [`decorate`](https://fastify.dev/docs/v5.3.x/Reference/Decorators/)
, tell Fastify not to create a new scope. Otherwise, changes will not be accessible in the upper scope.
There are two ways to avoid creating a new context:
* Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
module
* Use the `'skip-override'` hidden property
Using the `fastify-plugin` module is recommended, as it solves this problem and allows passing a version range of Fastify that the plugin will support:
const fp = require('fastify-plugin')module.exports = fp(function (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}, '0.x')
Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
documentation to learn more about how to use this module.
If not using `fastify-plugin`, the `'skip-override'` hidden property can be used, but it is not recommended. Future Fastify API changes will be your responsibility to update, whilst `fastify-plugin` ensures backward compatibility.
function yourPlugin (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}yourPlugin[Symbol.for('skip-override')] = truemodule.exports = yourPlugin
* [Plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#plugins)
* [Plugin Options](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#plugin-options)
* [async/await](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#asyncawait)
* [Create a plugin](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#create-a-plugin)
* [Handle the scope](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#handle-the-scope)
---
# Type-Providers | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Type Providers[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#type-providers "Direct link to Type Providers")
----------------------------------------------------------------------------------------------------------------------------
Type Providers are a TypeScript feature that enables Fastify to infer type information from inline JSON Schema. They are an alternative to specifying generic arguments on routes and can reduce the need to keep associated types for each schema in a project.
### Providers[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#providers "Direct link to Providers")
Official Type Provider packages follow the `@fastify/type-provider-{provider-name}` naming convention. Several community providers are also available.
The following inference packages are supported:
* [`json-schema-to-ts`](https://github.com/ThomasAribart/json-schema-to-ts)
* [`typebox`](https://github.com/sinclairzx81/typebox)
* [`zod`](https://github.com/colinhacks/zod)
See also the Type Provider wrapper packages for each of the packages respectively:
* [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
* [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
* [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
(3rd party)
### Json Schema to Ts[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#json-schema-to-ts "Direct link to Json Schema to Ts")
The following sets up a `json-schema-to-ts` Type Provider:
$ npm i @fastify/type-provider-json-schema-to-ts
import fastify from 'fastify'import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'const server = fastify().withTypeProvider()server.get('/route', { schema: { querystring: { type: 'object', properties: { foo: { type: 'number' }, bar: { type: 'string' }, }, required: ['foo', 'bar'] } }}, (request, reply) => { // type Query = { foo: number, bar: string } const { foo, bar } = request.query // type safe!})
### TypeBox[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#typebox "Direct link to TypeBox")
The following sets up a TypeBox Type Provider:
$ npm i @fastify/type-provider-typebox
import fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { Type } from '@sinclair/typebox'const server = fastify().withTypeProvider()server.get('/route', { schema: { querystring: Type.Object({ foo: Type.Number(), bar: Type.String() }) }}, (request, reply) => { // type Query = { foo: number, bar: string } const { foo, bar } = request.query // type safe!})
See the [TypeBox documentation](https://github.com/sinclairzx81/typebox#validation)
for setting up AJV to work with TypeBox.
### Zod[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#zod "Direct link to Zod")
See [official documentation](https://github.com/turkerdev/fastify-type-provider-zod)
for Zod Type Provider instructions.
### Scoped Type-Provider[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#scoped-type-provider "Direct link to Scoped Type-Provider")
The provider types don't propagate globally. In encapsulated usage, one can remap the context to use one or more providers (for example, `typebox` and `json-schema-to-ts` can be used in the same application).
Example:
import Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'import { Type } from '@sinclair/typebox'const fastify = Fastify()function pluginWithTypebox(fastify: FastifyInstance, _opts, done): void { fastify.withTypeProvider() .get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { const { x, y, z } = req.body // type safe }); done()}function pluginWithJsonSchema(fastify: FastifyInstance, _opts, done): void { fastify.withTypeProvider() .get('/', { schema: { body: { type: 'object', properties: { x: { type: 'string' }, y: { type: 'number' }, z: { type: 'boolean' } }, } } }, (req) => { const { x, y, z } = req.body // type safe }); done()}fastify.register(pluginWithJsonSchema)fastify.register(pluginWithTypebox)
It is important to note that since the types do not propagate globally, it is currently not possible to avoid multiple registrations on routes when dealing with several scopes, as shown below:
import Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { Type } from '@sinclair/typebox'const server = Fastify().withTypeProvider()server.register(plugin1) // wrongserver.register(plugin2) // correctfunction plugin1(fastify: FastifyInstance, _opts, done): void { fastify.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // In a new scope, call `withTypeProvider` again to ensure it works const { x, y, z } = req.body }); done()}function plugin2(fastify: FastifyInstance, _opts, done): void { const server = fastify.withTypeProvider() server.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // works const { x, y, z } = req.body }); done()}
### Type Definition of FastifyInstance + TypeProvider[](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#type-definition-of-fastifyinstance--typeprovider "Direct link to Type Definition of FastifyInstance + TypeProvider")
When working with modules, use `FastifyInstance` with Type Provider generics. See the example below:
// index.tsimport Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { registerRoutes } from './routes'const server = Fastify().withTypeProvider()registerRoutes(server)server.listen({ port: 3000 })
// routes.tsimport { Type } from '@sinclair/typebox'import { FastifyInstance, FastifyBaseLogger, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault} from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'type FastifyTypebox = FastifyInstance< RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, FastifyBaseLogger, TypeBoxTypeProvider>;export function registerRoutes(fastify: FastifyTypebox): void { fastify.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // works const { x, y, z } = req.body });}
* [Type Providers](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#type-providers)
* [Providers](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#providers)
* [Json Schema to Ts](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#json-schema-to-ts)
* [TypeBox](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#typebox)
* [Zod](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#zod)
* [Scoped Type-Provider](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#scoped-type-provider)
* [Type Definition of FastifyInstance + TypeProvider](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/#type-definition-of-fastifyinstance--typeprovider)
---
# Hooks | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Hooks[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#hooks "Direct link to Hooks")
----------------------------------------------------------------------------------------
Hooks are registered with the `fastify.addHook` method and allow you to listen to specific events in the application or request/response lifecycle. You have to register a hook before the event is triggered, otherwise, the event is lost.
By using hooks you can interact directly with the lifecycle of Fastify. There are Request/Reply hooks and application hooks:
* [Request/Reply Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#diagnostics-channel-hooks)
> ℹ️ Note: The `done` callback is not available when using `async`/`await` or returning a `Promise`. If you do invoke a `done` callback in this situation unexpected behavior may occur, e.g. duplicate invocation of handlers.
Request/Reply Hooks[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#requestreply-hooks "Direct link to Request/Reply Hooks")
---------------------------------------------------------------------------------------------------------------------------------
[Request](https://fastify.dev/docs/v5.4.x/Reference/Request/)
and [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/)
are the core Fastify objects.
`done` is the function to continue with the [lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/)
.
It is easy to understand where each hook is executed by looking at the [lifecycle page](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/)
.
Hooks are affected by Fastify's encapsulation, and can thus be applied to selected routes. See the [Scopes](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#scope)
section for more information.
There are eight different hooks that you can use in Request/Reply _(in order of execution)_:
### onRequest[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest "Direct link to onRequest")
fastify.addHook('onRequest', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequest', async (request, reply) => { // Some code await asyncMethod()})
> ℹ️ Note: In the [onRequest](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
> hook.
### preParsing[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing "Direct link to preParsing")
If you are using the `preParsing` hook, you can transform the request payload stream before it is parsed. It receives the request and reply objects as other hooks, and a stream with the current request payload.
If it returns a value (via `return` or via the callback function), it must return a stream.
For instance, you can decompress the request body:
fastify.addHook('preParsing', (request, reply, payload, done) => { // Some code done(null, newPayload)})
Or `async/await`:
fastify.addHook('preParsing', async (request, reply, payload) => { // Some code await asyncMethod() return newPayload})
> ℹ️ Note: In the [preParsing](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
> hook.
> ℹ️ Note: You should also add a `receivedEncodedLength` property to the returned stream. This property is used to correctly match the request payload with the `Content-Length` header value. Ideally, this property should be updated on each received chunk.
> ℹ️ Note: The size of the returned stream is checked to not exceed the limit set in [`bodyLimit`](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit)
> option.
### preValidation[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation "Direct link to preValidation")
If you are using the `preValidation` hook, you can change the payload before it is validated. For example:
fastify.addHook('preValidation', (request, reply, done) => { request.body = { ...request.body, importantKey: 'randomString' } done()})
Or `async/await`:
fastify.addHook('preValidation', async (request, reply) => { const importantKey = await generateRandomString() request.body = { ...request.body, importantKey }})
### preHandler[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prehandler "Direct link to preHandler")
The `preHandler` hook allows you to specify a function that is executed before a routes's handler.
fastify.addHook('preHandler', (request, reply, done) => { // some code done()})
Or `async/await`:
fastify.addHook('preHandler', async (request, reply) => { // Some code await asyncMethod()})
### preSerialization[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preserialization "Direct link to preSerialization")
If you are using the `preSerialization` hook, you can change (or replace) the payload before it is serialized. For example:
fastify.addHook('preSerialization', (request, reply, payload, done) => { const err = null const newPayload = { wrapped: payload } done(err, newPayload)})
Or `async/await`:
fastify.addHook('preSerialization', async (request, reply, payload) => { return { wrapped: payload }})
> ℹ️ Note: The hook is NOT called if the payload is a `string`, a `Buffer`, a `stream`, or `null`.
### onError[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onerror "Direct link to onError")
fastify.addHook('onError', (request, reply, error, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onError', async (request, reply, error) => { // Useful for custom error logging // You should not use this hook to update the error})
This hook is useful if you need to do some custom error logging or add some specific header in case of error.
It is not intended for changing the error, and calling `reply.send` will throw an exception.
This hook will be executed only after the [Custom Error Handler set by `setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
has been executed, and only if the custom error handler sends an error back to the user _(Note that the default error handler always sends the error back to the user)_.
> ℹ️ Note: Unlike the other hooks, passing an error to the `done` function is not supported.
### onSend[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onsend "Direct link to onSend")
If you are using the `onSend` hook, you can change the payload. For example:
fastify.addHook('onSend', (request, reply, payload, done) => { const err = null; const newPayload = payload.replace('some-text', 'some-new-text') done(err, newPayload)})
Or `async/await`:
fastify.addHook('onSend', async (request, reply, payload) => { const newPayload = payload.replace('some-text', 'some-new-text') return newPayload})
You can also clear the payload to send a response with an empty body by replacing the payload with `null`:
fastify.addHook('onSend', (request, reply, payload, done) => { reply.code(304) const newPayload = null done(null, newPayload)})
> You can also send an empty body by replacing the payload with the empty string `''`, but be aware that this will cause the `Content-Length` header to be set to `0`, whereas the `Content-Length` header will not be set if the payload is `null`.
> ℹ️ Note: If you change the payload, you may only change it to a `string`, a `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
### onResponse[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onresponse "Direct link to onResponse")
fastify.addHook('onResponse', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onResponse', async (request, reply) => { // Some code await asyncMethod()})
The `onResponse` hook is executed when a response has been sent, so you will not be able to send more data to the client. It can however be useful for sending data to external services, for example, to gather statistics.
> ℹ️ Note: Setting `disableRequestLogging` to `true` will disable any error log inside the `onResponse` hook. In this case use `try - catch` to log errors.
### onTimeout[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#ontimeout "Direct link to onTimeout")
fastify.addHook('onTimeout', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onTimeout', async (request, reply) => { // Some code await asyncMethod()})
`onTimeout` is useful if you need to monitor the request timed out in your service (if the `connectionTimeout` property is set on the Fastify instance). The `onTimeout` hook is executed when a request is timed out and the HTTP socket has been hung up. Therefore, you will not be able to send data to the client.
### onRequestAbort[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequestabort "Direct link to onRequestAbort")
fastify.addHook('onRequestAbort', (request, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequestAbort', async (request) => { // Some code await asyncMethod()})
The `onRequestAbort` hook is executed when a client closes the connection before the entire request has been processed. Therefore, you will not be able to send data to the client.
> ℹ️ Note: Client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](https://fastify.dev/docs/v5.4.x/Guides/Detecting-When-Clients-Abort/)
### Manage Errors from a hook[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#manage-errors-from-a-hook "Direct link to Manage Errors from a hook")
If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
fastify.addHook('onRequest', (request, reply, done) => { done(new Error('Some error'))})
If you want to pass a custom error code to the user, just use `reply.code()`:
fastify.addHook('preHandler', (request, reply, done) => { reply.code(400) done(new Error('Some error'))})
_The error will be handled by [`Reply`](https://fastify.dev/docs/v5.4.x/Reference/Reply/#errors)
._
Or if you're using `async/await` you can just throw an error:
fastify.addHook('onRequest', async (request, reply) => { throw new Error('Some error')})
### Respond to a request from a hook[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#respond-to-a-request-from-a-hook "Direct link to Respond to a request from a hook")
If needed, you can respond to a request before you reach the route handler, for example when implementing an authentication hook. Replying from a hook implies that the hook chain is **stopped** and the rest of the hooks and handlers are not executed. If the hook is using the callback approach, i.e. it is not an `async` function or it returns a `Promise`, it is as simple as calling `reply.send()` and avoiding calling the callback. If the hook is `async`, `reply.send()` **must** be called _before_ the function returns or the promise resolves, otherwise, the request will proceed. When `reply.send()` is called outside of the promise chain, it is important to `return reply` otherwise the request will be executed twice.
It is important to **not mix callbacks and `async`/`Promise`**, otherwise the hook chain will be executed twice.
If you are using `onRequest` or `preHandler` use `reply.send`.
fastify.addHook('onRequest', (request, reply, done) => { reply.send('Early response')})// Works with async functions toofastify.addHook('preHandler', async (request, reply) => { setTimeout(() => { reply.send({ hello: 'from prehandler' }) }) return reply // mandatory, so the request is not executed further// Commenting the line above will allow the hooks to continue and fail with FST_ERR_REP_ALREADY_SENT})
If you want to respond with a stream, you should avoid using an `async` function for the hook. If you must use an `async` function, your code will need to follow the pattern in [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275)
.
fastify.addHook('onRequest', (request, reply, done) => { const stream = fs.createReadStream('some-file', 'utf8') reply.send(stream)})
If you are sending a response without `await` on it, make sure to always `return reply`:
fastify.addHook('preHandler', async (request, reply) => { setImmediate(() => { reply.send('hello') }) // This is needed to signal the handler to wait for a response // to be sent outside of the promise chain return reply})fastify.addHook('preHandler', async (request, reply) => { // the @fastify/static plugin will send a file asynchronously, // so we should return reply reply.sendFile('myfile') return reply})
Application Hooks[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#application-hooks "Direct link to Application Hooks")
----------------------------------------------------------------------------------------------------------------------------
You can hook into the application-lifecycle as well.
* [onReady](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onregister)
### onReady[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onready "Direct link to onReady")
Triggered before the server starts listening for requests and when `.ready()` is invoked. It cannot change the routes or add new hooks. Registered hook functions are executed serially. Only after all `onReady` hook functions have completed will the server start listening for requests. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
// callback stylefastify.addHook('onReady', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onReady', async function () { // Some async code await loadCacheFromDatabase()})
### onListen[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onlisten "Direct link to onListen")
Triggered when the server starts listening for requests. The hooks run one after another. If a hook function causes an error, it is logged and ignored, allowing the queue of hooks to continue. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
This is an alternative to `fastify.server.on('listening', () => {})`.
// callback stylefastify.addHook('onListen', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onListen', async function () { // Some async code})
> ℹ️ Note: This hook will not run when the server is started using fastify.inject()`or`fastify.ready()\`.
### onClose[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose "Direct link to onClose")
Triggered when `fastify.close()` is invoked to stop the server, after all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
need a "shutdown" event, for example, to close an open connection to a database.
The hook function takes the Fastify instance as a first argument, and a `done` callback for synchronous hook functions.
// callback stylefastify.addHook('onClose', (instance, done) => { // Some code done()})// or async/await stylefastify.addHook('onClose', async (instance) => { // Some async code await closeDatabaseConnections()})
### preClose[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preclose "Direct link to preClose")
Triggered when `fastify.close()` is invoked to stop the server, before all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
have set up some state attached to the HTTP server that would prevent the server to close. _It is unlikely you will need to use this hook_, use the [`onClose`](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose)
for the most common case.
// callback stylefastify.addHook('preClose', (done) => { // Some code done()})// or async/await stylefastify.addHook('preClose', async () => { // Some async code await removeSomeServerState()})
### onRoute[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onroute "Direct link to onRoute")
Triggered when a new route is registered. Listeners are passed a [`routeOptions`](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-options)
object as the sole parameter. The interface is synchronous, and, as such, the listeners are not passed a callback. This hook is encapsulated.
fastify.addHook('onRoute', (routeOptions) => { //Some code routeOptions.method routeOptions.schema routeOptions.url // the complete URL of the route, it will include the prefix if any routeOptions.path // `url` alias routeOptions.routePath // the URL of the route without the prefix routeOptions.bodyLimit routeOptions.logLevel routeOptions.logSerializers routeOptions.prefix})
If you are authoring a plugin and you need to customize application routes, like modifying the options or adding new route hooks, this is the right place.
fastify.addHook('onRoute', (routeOptions) => { function onPreSerialization(request, reply, payload, done) { // Your code done(null, payload) } // preSerialization can be an array or undefined routeOptions.preSerialization = [...(routeOptions.preSerialization || []), onPreSerialization]})
To add more routes within an onRoute hook, the routes must be tagged correctly. The hook will run into an infinite loop if not tagged. The recommended approach is shown below.
const kRouteAlreadyProcessed = Symbol('route-already-processed')fastify.addHook('onRoute', function (routeOptions) { const { url, method } = routeOptions const isAlreadyProcessed = (routeOptions.custom && routeOptions.custom[kRouteAlreadyProcessed]) || false if (!isAlreadyProcessed) { this.route({ url, method, custom: { [kRouteAlreadyProcessed]: true }, handler: () => {} }) }})
For more details, see this [issue](https://github.com/fastify/fastify/issues/4319)
.
### onRegister[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onregister "Direct link to onRegister")
Triggered when a new plugin is registered and a new encapsulation context is created. The hook will be executed **before** the registered code.
This hook can be useful if you are developing a plugin that needs to know when a plugin context is formed, and you want to operate in that specific context, thus this hook is encapsulated.
> ℹ️ Note: This hook will not be called if a plugin is wrapped inside [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
> .
fastify.decorate('data', [])fastify.register(async (instance, opts) => { instance.data.push('hello') console.log(instance.data) // ['hello'] instance.register(async (instance, opts) => { instance.data.push('world') console.log(instance.data) // ['hello', 'world'] }, { prefix: '/hola' })}, { prefix: '/ciao' })fastify.register(async (instance, opts) => { console.log(instance.data) // []}, { prefix: '/hello' })fastify.addHook('onRegister', (instance, opts) => { // Create a new array from the old one // but without keeping the reference // allowing the user to have encapsulated // instances of the `data` property instance.data = instance.data.slice() // the options of the new registered instance console.log(opts.prefix)})
Scope[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#scope "Direct link to Scope")
----------------------------------------------------------------------------------------
Except for [onClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose)
, all hooks are encapsulated. This means that you can decide where your hooks should run by using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.4.x/Guides/Plugins-Guide/)
. If you pass a function, that function is bound to the right Fastify context and from there you have full access to the Fastify API.
fastify.addHook('onRequest', function (request, reply, done) { const self = this // Fastify context done()})
Note that the Fastify context in each hook is the same as the plugin where the route was registered, for example:
fastify.addHook('onRequest', async function (req, reply) { if (req.raw.url === '/nested') { assert.strictEqual(this.foo, 'bar') } else { assert.strictEqual(this.foo, undefined) }})fastify.get('/', async function (req, reply) { assert.strictEqual(this.foo, undefined) return { hello: 'world' }})fastify.register(async function plugin (fastify, opts) { fastify.decorate('foo', 'bar') fastify.get('/nested', async function (req, reply) { assert.strictEqual(this.foo, 'bar') return { hello: 'world' } })})
Warn: if you declare the function with an [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
, the `this` will not be Fastify, but the one of the current scope.
Route level hooks[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-level-hooks "Direct link to Route level hooks")
----------------------------------------------------------------------------------------------------------------------------
You can declare one or more custom lifecycle hooks ([onRequest](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
, [onResponse](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onresponse)
, [preParsing](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
, [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
, [preHandler](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prehandler)
, [preSerialization](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preserialization)
, [onSend](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onsend)
, [onTimeout](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#ontimeout)
, and [onError](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onerror)
) hook(s) that will be **unique** for the route. If you do so, those hooks are always executed as the last hook in their category.
This can be useful if you need to implement authentication, where the [preParsing](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
or [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
hooks are exactly what you need. Multiple route-level hooks can also be specified as an array.
fastify.addHook('onRequest', (request, reply, done) => { // Your code done()})fastify.addHook('onResponse', (request, reply, done) => { // your code done()})fastify.addHook('preParsing', (request, reply, done) => { // Your code done()})fastify.addHook('preValidation', (request, reply, done) => { // Your code done()})fastify.addHook('preHandler', (request, reply, done) => { // Your code done()})fastify.addHook('preSerialization', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onSend', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onTimeout', (request, reply, done) => { // Your code done()})fastify.addHook('onError', (request, reply, error, done) => { // Your code done()})fastify.route({ method: 'GET', url: '/', schema: { ... }, onRequest: function (request, reply, done) { // This hook will always be executed after the shared `onRequest` hooks done() }, // // Example with an async hook. All hooks support this syntax // // onRequest: async function (request, reply) { // // This hook will always be executed after the shared `onRequest` hooks // await ... // } onResponse: function (request, reply, done) { // this hook will always be executed after the shared `onResponse` hooks done() }, preParsing: function (request, reply, done) { // This hook will always be executed after the shared `preParsing` hooks done() }, preValidation: function (request, reply, done) { // This hook will always be executed after the shared `preValidation` hooks done() }, preHandler: function (request, reply, done) { // This hook will always be executed after the shared `preHandler` hooks done() }, // // Example with an array. All hooks support this syntax. // // preHandler: [function (request, reply, done) { // // This hook will always be executed after the shared `preHandler` hooks // done() // }], preSerialization: (request, reply, payload, done) => { // This hook will always be executed after the shared `preSerialization` hooks done(null, payload) }, onSend: (request, reply, payload, done) => { // This hook will always be executed after the shared `onSend` hooks done(null, payload) }, onTimeout: (request, reply, done) => { // This hook will always be executed after the shared `onTimeout` hooks done() }, onError: (request, reply, error, done) => { // This hook will always be executed after the shared `onError` hooks done() }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})
> ℹ️ Note: Both options also accept an array of functions.
Using Hooks to Inject Custom Properties[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#using-hooks-to-inject-custom-properties "Direct link to Using Hooks to Inject Custom Properties")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
You can use a hook to inject custom properties into incoming requests. This is useful for reusing processed data from hooks in controllers.
A very common use case is, for example, checking user authentication based on their token and then storing their recovered data into the [Request](https://fastify.dev/docs/v5.4.x/Reference/Request/)
instance. This way, your controllers can read it easily with `request.authenticatedUser` or whatever you want to call it. That's how it might look like:
fastify.addHook('preParsing', async (request) => { request.authenticatedUser = { id: 42, name: 'Jane Doe', role: 'admin' }})fastify.get('/me/is-admin', async function (req, reply) { return { isAdmin: req.authenticatedUser?.role === 'admin' || false }})
Note that `.authenticatedUser` could actually be any property name chosen by yourself. Using your own custom property prevents you from mutating existing properties, which would be a dangerous and destructive operation. So be careful and make sure your property is entirely new, also using this approach only for very specific and small cases like this example.
Regarding TypeScript in this example, you'd need to update the `FastifyRequest` core interface to include your new property typing (for more about it, see [TypeScript](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/)
page), like:
interface AuthenticatedUser { /* ... */ }declare module 'fastify' { export interface FastifyRequest { authenticatedUser?: AuthenticatedUser; }}
Although this is a very pragmatic approach, if you're trying to do something more complex that changes these core objects, then consider creating a custom [Plugin](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
instead.
Diagnostics Channel Hooks[](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#diagnostics-channel-hooks "Direct link to Diagnostics Channel Hooks")
----------------------------------------------------------------------------------------------------------------------------------------------------
One [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
publish event, `'fastify.initialization'`, happens at initialization time. The Fastify instance is passed into the hook as a property of the object passed in. At this point, the instance can be interacted with to add hooks, plugins, routes, or any other sort of modification.
For example, a tracing package might do something like the following (which is, of course, a simplification). This would be in a file loaded in the initialization of the tracking package, in the typical "require instrumentation tools first" fashion.
const tracer = /* retrieved from elsewhere in the package */const dc = require('node:diagnostics_channel')const channel = dc.channel('fastify.initialization')const spans = new WeakMap()channel.subscribe(function ({ fastify }) { fastify.addHook('onRequest', (request, reply, done) => { const span = tracer.startSpan('fastify.request.handler') spans.set(request, span) done() }) fastify.addHook('onResponse', (request, reply, done) => { const span = spans.get(request) span.finish() done() })})
> ℹ️ Note: The TracingChannel class API is currently experimental and may undergo breaking changes even in semver-patch releases of Node.js.
Five other events are published on a per-request basis following the [Tracing Channel](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel)
nomenclature. The list of the channel names and the event they receive is:
* `tracing:fastify.request.handler:start`: Always fires
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:end`: Always fires
* `{ request: Request, reply: Reply, route: { url, method }, async: Bool }`
* `tracing:fastify.request.handler:asyncStart`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:asyncEnd`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:error`: Fires when an error occurs
* `{ request: Request, reply: Reply, route: { url, method }, error: Error }`
The object instance remains the same for all events associated with a given request. All payloads include a `request` and `reply` property which are an instance of Fastify's `Request` and `Reply` instances. They also include a `route` property which is an object with the matched `url` pattern (e.g. `/collection/:id`) and the `method` HTTP method (e.g. `GET`). The `:start` and `:end` events always fire for requests. If a request handler is an `async` function or one that returns a `Promise` then the `:asyncStart` and `:asyncEnd` events also fire. Finally, the `:error` event contains an `error` property associated with the request's failure.
These events can be received like so:
const dc = require('node:diagnostics_channel')const channel = dc.channel('tracing:fastify.request.handler:start')channel.subscribe((msg) => { console.log(msg.request, msg.reply)})
* [Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#hooks)
* [Request/Reply Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#diagnostics-channel-hooks)
---
# Reply | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Reply/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Reply[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply "Direct link to Reply")
----------------------------------------------------------------------------------------
* [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.4.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.4.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.4.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.4.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headerkey-value)
* [.headers(object)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#redirectdest--code)
* [.callNotFound()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getserializationfunctionschema--httpstatus)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#compileserializationschemaschema-httpstatus)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus)
* [.serializer(func)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.4.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.4.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#senddata)
* [Objects](https://fastify.dev/docs/v5.4.x/Reference/Reply/#objects)
* [Strings](https://fastify.dev/docs/v5.4.x/Reference/Reply/#strings)
* [Streams](https://fastify.dev/docs/v5.4.x/Reference/Reply/#streams)
* [Buffers](https://fastify.dev/docs/v5.4.x/Reference/Reply/#buffers)
* [TypedArrays](https://fastify.dev/docs/v5.4.x/Reference/Reply/#typedarrays)
* [ReadableStream](https://fastify.dev/docs/v5.4.x/Reference/Reply/#readablestream)
* [Response](https://fastify.dev/docs/v5.4.x/Reference/Reply/#response)
* [Errors](https://fastify.dev/docs/v5.4.x/Reference/Reply/#errors)
* [Type of the final payload](https://fastify.dev/docs/v5.4.x/Reference/Reply/#type-of-the-final-payload)
* [Async-Await and Promises](https://fastify.dev/docs/v5.4.x/Reference/Reply/#async-await-and-promises)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#thenfulfilled-rejected)
### Introduction[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#introduction "Direct link to Introduction")
The second parameter of the handler function is `Reply`. Reply is a core Fastify object that exposes the following functions and properties:
* `.code(statusCode)` - Sets the status code.
* `.status(statusCode)` - An alias for `.code(statusCode)`.
* `.statusCode` - Read and set the HTTP status code.
* `.elapsedTime` - Returns the amount of time passed since the request was received by Fastify.
* `.server` - A reference to the fastify instance object.
* `.header(name, value)` - Sets a response header.
* `.headers(object)` - Sets all the keys of the object as response headers.
* `.getHeader(name)` - Retrieve value of already set header.
* `.getHeaders()` - Gets a shallow copy of all current response headers.
* `.removeHeader(key)` - Remove the value of a previously set header.
* `.hasHeader(name)` - Determine if a header has been set.
* `.writeEarlyHints(hints, callback)` - Sends early hints to the user while the response is being prepared.
* `.trailer(key, function)` - Sets a response trailer.
* `.hasTrailer(key)` - Determine if a trailer has been set.
* `.removeTrailer(key)` - Remove the value of a previously set trailer.
* `.type(value)` - Sets the header `Content-Type`.
* `.redirect(dest, [code,])` - Redirect to the specified URL, the status code is optional (defaults to `302`).
* `.callNotFound()` - Invokes the custom not found handler.
* `.serialize(payload)` - Serializes the specified payload using the default JSON serializer or using the custom serializer (if one is set) and returns the serialized payload.
* `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the serialization function for the specified schema or http status, if any of either are set.
* `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles the specified schema and returns a serialization function using the default (or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded to the `SerializerCompiler` if provided, default to `undefined`.
* `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes the specified data using the specified schema and returns the serialized payload. If the optional `httpStatus`, and `contentType` are provided, the function will use the serializer function given for that specific content type and HTTP Status Code. Default to `undefined`.
* `.serializer(function)` - Sets a custom serializer for the payload.
* `.send(payload)` - Sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object.
* `.sent` - A boolean value that you can use if you need to know if `send` has already been called.
* `.hijack()` - interrupt the normal request lifecycle.
* `.raw` - The [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core.
* `.log` - The logger instance of the incoming request.
* `.request` - The incoming request.
fastify.get('/', options, function (request, reply) { // Your code reply .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ hello: 'world' })})
### .code(statusCode)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#codestatuscode "Direct link to .code(statusCode)")
If not set via `reply.code`, the resulting `statusCode` will be `200`.
### .elapsedTime[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#elapsedtime "Direct link to .elapsedTime")
Invokes the custom response time getter to calculate the amount of time passed since the request was received by Fastify.
const milliseconds = reply.elapsedTime
### .statusCode[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#statuscode "Direct link to .statusCode")
This property reads and sets the HTTP status code. It is an alias for `reply.code()` when used as a setter.
if (reply.statusCode >= 299) { reply.statusCode = 500}
### .server[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#server "Direct link to .server")
The Fastify server instance, scoped to the current [encapsulation context](https://fastify.dev/docs/v5.4.x/Reference/Encapsulation/)
.
fastify.decorate('util', function util () { return 'foo'})fastify.get('/', async function (req, rep) { return rep.server.util() // foo})
### .header(key, value)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headerkey-value "Direct link to .header(key, value)")
Sets a response header. If the value is omitted or undefined, it is coerced to `''`.
> ℹ️ Note: The header's value must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid characters will result in a 500 `TypeError` response.
For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value)
.
* ### set-cookie[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#set-cookie "Direct link to set-cookie")
* When sending different values as a cookie with `set-cookie` as the key, every value will be sent as a cookie instead of replacing the previous value.
reply.header('set-cookie', 'foo');reply.header('set-cookie', 'bar');
* The browser will only consider the latest reference of a key for the `set-cookie` header. This is done to avoid parsing the `set-cookie` header when added to a reply and speeds up the serialization of the reply.
* To reset the `set-cookie` header, you need to make an explicit call to `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)` [here](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removeheaderkey)
.
### .headers(object)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headersobject "Direct link to .headers(object)")
Sets all the keys of the object as response headers. [`.header`](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headerkey-value)
will be called under the hood.
reply.headers({ 'x-foo': 'foo', 'x-bar': 'bar'})
### .getHeader(key)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaderkey "Direct link to .getHeader(key)")
Retrieves the value of a previously set header.
reply.header('x-foo', 'foo') // setHeader: key, valuereply.getHeader('x-foo') // 'foo'
### .getHeaders()[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaders "Direct link to .getHeaders()")
Gets a shallow copy of all current response headers, including those set via the raw `http.ServerResponse`. Note that headers set via Fastify take precedence over those set via `http.ServerResponse`.
reply.header('x-foo', 'foo')reply.header('x-bar', 'bar')reply.raw.setHeader('x-foo', 'foo2')reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
### .removeHeader(key)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removeheaderkey "Direct link to .removeHeader(key)")
Remove the value of a previously set header.
reply.header('x-foo', 'foo')reply.removeHeader('x-foo')reply.getHeader('x-foo') // undefined
### .hasHeader(key)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hasheaderkey "Direct link to .hasHeader(key)")
Returns a boolean indicating if the specified header has been set.
### .writeEarlyHints(hints, callback)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#writeearlyhintshints-callback "Direct link to .writeEarlyHints(hints, callback)")
Sends early hints to the client. Early hints allow the client to start processing resources before the final response is sent. This can improve performance by allowing the client to preload or preconnect to resources while the server is still generating the response.
The hints parameter is an object containing the early hint key-value pairs.
Example:
reply.writeEarlyHints({ Link: '; rel=preload; as=style'});
The optional callback parameter is a function that will be called once the hint is sent or if an error occurs.
### .trailer(key, function)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#trailerkey-function "Direct link to .trailer(key, function)")
Sets a response trailer. Trailer is usually used when you need a header that requires heavy resources to be sent after the `data`, for example, `Server-Timing` and `Etag`. It can ensure the client receives the response data as soon as possible.
> ℹ️ Note: The header `Transfer-Encoding: chunked` will be added once you use the trailer. It is a hard requirement for using trailer in Node.js.
> ℹ️ Note: Any error passed to `done` callback will be ignored. If you interested in the error, you can turn on `debug` level logging.\*
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})const { createHash } = require('node:crypto')// trailer function also receive two argument// @param {object} reply fastify reply// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent// @param {function} done callback to set trailer valuereply.trailer('content-md5', function(reply, payload, done) { const hash = createHash('md5') hash.update(payload) done(null, hash.digest('hex'))})// when you prefer async-awaitreply.trailer('content-md5', async function(reply, payload) { const hash = createHash('md5') hash.update(payload) return hash.digest('hex')})
### .hasTrailer(key)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hastrailerkey "Direct link to .hasTrailer(key)")
Returns a boolean indicating if the specified trailer has been set.
### .removeTrailer(key)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removetrailerkey "Direct link to .removeTrailer(key)")
Remove the value of a previously set trailer.
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})reply.removeTrailer('server-timing')reply.getTrailer('server-timing') // undefined
### .redirect(dest, \[code ,\])[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#redirectdest-code- "Direct link to .redirect(dest, [code ,])")
Redirects a request to the specified URL, the status code is optional, default to `302` (if status code is not already set by calling `code`).
> ℹ️ Note: The input URL must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid URLs will result in a 500 `TypeError` response.
Example (no `reply.code()` call) sets status code to `302` and redirects to `/home`
reply.redirect('/home')
Example (no `reply.code()` call) sets status code to `303` and redirects to `/home`
reply.redirect('/home', 303)
Example (`reply.code()` call) sets status code to `303` and redirects to `/home`
reply.code(303).redirect('/home')
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
reply.code(303).redirect('/home', 302)
### .callNotFound()[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#callnotfound "Direct link to .callNotFound()")
Invokes the custom not found handler. Note that it will only call `preHandler` hook specified in [`setNotFoundHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#set-not-found-handler)
.
reply.callNotFound()
### .type(contentType)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#typecontenttype "Direct link to .type(contentType)")
Sets the content type for the response. This is a shortcut for `reply.header('Content-Type', 'the/type')`.
reply.type('text/html')
If the `Content-Type` has a JSON subtype, and the charset parameter is not set, `utf-8` will be used as the charset by default. For other content types, the charset must be set explicitly.
### .getSerializationFunction(schema | httpStatus, \[contentType\])[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype "Direct link to .getSerializationFunction(schema | httpStatus, [contentType])")
By calling this function using a provided `schema` or `httpStatus`, and the optional `contentType`, it will return a `serialzation` function that can be used to serialize diverse inputs. It returns `undefined` if no serialization function was found using either of the provided inputs.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .getSerializationFunction({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200, 'application/json')serialize({ foo: 'bar' }) // '{"foo":"bar"}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .compileSerializationSchema(schema, \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype "Direct link to .compileSerializationSchema(schema, [httpStatus], [contentType])")
This function will compile a serialization schema and return a function that can be used to serialize data. The function returned (a.k.a. _serialization function_) returned is compiled by using the provided `SerializerCompiler`. Also this is cached by using a `WeakMap` for reducing compilation calls.
The optional parameters `httpStatus` and `contentType`, if provided, are forwarded directly to the `SerializerCompiler`, so it can be used to compile the serialization function if a custom `SerializerCompiler` is used.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } }, 200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ '3xx': { content: { 'application/json': { schema: { name: { type: 'string' }, phone: { type: 'number' } } } } } }, '3xx', 'application/json')serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
Note that you should be careful when using this function, as it will cache the compiled serialization functions based on the schema provided. If the schemas provided is mutated or changed, the serialization functions will not detect that the schema has been altered and for instance it will reuse the previously compiled serialization function based on the reference of the schema previously provided.
If there's a need to change the properties of a schema, always opt to create a totally new object, otherwise the implementation won't benefit from the cache mechanism.
:Using the following schema as example:
const schema1 = { type: 'object', properties: { foo: { type: 'string' } }}
_Not_
const serialize = reply.compileSerializationSchema(schema1)// Later on...schema1.properties.foo.type. = 'integer'const newSerialize = reply.compileSerializationSchema(schema1)console.log(newSerialize === serialize) // true
_Instead_
const serialize = reply.compileSerializationSchema(schema1)// Later on...const newSchema = Object.assign({}, schema1)newSchema.properties.foo.type = 'integer'const newSerialize = reply.compileSerializationSchema(newSchema)console.log(newSerialize === serialize) // false
### .serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype "Direct link to .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])")
This function will serialize the input data based on the provided schema or HTTP status code. If both are provided the `httpStatus` will take precedence.
If there is not a serialization function for a given `schema` a new serialization function will be compiled, forwarding the `httpStatus` and `contentType` if provided.
reply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }, 200) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'// orreply .serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .serializer(func)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializerfunc "Direct link to .serializer(func)")
By default, `.send()` will JSON-serialize any value that is not one of `Buffer`, `stream`, `string`, `undefined`, or `Error`. If you need to replace the default serializer with a custom serializer for a particular request, you can do so with the `.serializer()` utility. Be aware that if you are using a custom serializer, you must set a custom `'Content-Type'` header.
reply .header('Content-Type', 'application/x-protobuf') .serializer(protoBuf.serialize)
Note that you don't need to use this utility inside a `handler` because Buffers, streams, and strings (unless a serializer is set) are considered to already be serialized.
reply .header('Content-Type', 'application/x-protobuf') .send(protoBuf.serialize(data))
See [`.send()`](https://fastify.dev/docs/v5.4.x/Reference/Reply/#send)
for more information on sending different types of values.
### .raw[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#raw "Direct link to .raw")
This is the [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core. Whilst you are using the Fastify `Reply` object, the use of `Reply.raw` functions is at your own risk as you are skipping all the Fastify logic of handling the HTTP response. e.g.:
app.get('/cookie-2', (req, reply) => { reply.setCookie('session', 'value', { secure: false }) // this will not be used // in this case we are using only the nodejs http server response object reply.raw.writeHead(200, { 'Content-Type': 'text/plain' }) reply.raw.write('ok') reply.raw.end()})
Another example of the misuse of `Reply.raw` is explained in [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaders)
.
### .sent[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#sent "Direct link to .sent")
As the name suggests, `.sent` is a property to indicate if a response has been sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was used.
In case a route handler is defined as an async function or it returns a promise, it is possible to call `reply.hijack()` to indicate that the automatic invocation of `reply.send()` once the handler promise resolve should be skipped. By calling `reply.hijack()`, an application claims full responsibility for the low-level request and response. Moreover, hooks will not be invoked.
_Modifying the `.sent` property directly is deprecated. Please use the aforementioned `.hijack()` method to achieve the same effect._
### .hijack()[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hijack "Direct link to .hijack()")
Sometimes you might need to halt the execution of the normal request lifecycle and handle sending the response manually.
To achieve this, Fastify provides the `reply.hijack()` method that can be called during the request lifecycle (At any point before `reply.send()` is called), and allows you to prevent Fastify from sending the response, and from running the remaining hooks (and user handler if the reply was hijacked before).
app.get('/', (req, reply) => { reply.hijack() reply.raw.end('hello world') return Promise.resolve('this will be skipped')})
If `reply.raw` is used to send a response back to the user, the `onResponse` hooks will still be executed.
### .send(data)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#senddata "Direct link to .send(data)")
As the name suggests, `.send()` is the function that sends the payload to the end user.
#### Objects[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#objects "Direct link to Objects")
As noted above, if you are sending JSON objects, `send` will serialize the object with [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
if you set an output schema, otherwise, `JSON.stringify()` will be used.
fastify.get('/json', options, function (request, reply) { reply.send({ hello: 'world' })})
#### Strings[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#strings "Direct link to Strings")
If you pass a string to `send` without a `Content-Type`, it will be sent as `text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a string to `send`, it will be serialized with the custom serializer if one is set, otherwise, it will be sent unmodified (unless the `Content-Type` header is set to `application/json; charset=utf-8`, in which case it will be JSON-serialized like an object — see the section above).
fastify.get('/json', options, function (request, reply) { reply.send('plain string')})
#### Streams[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#streams "Direct link to Streams")
If you are sending a stream and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, streams are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') reply.send(stream)})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') return reply.send(stream)})
#### Buffers[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#buffers "Direct link to Buffers")
If you are sending a buffer and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) })})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) }) return reply})
#### TypedArrays[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#typedarrays "Direct link to TypedArrays")
`send` manages TypedArray like a Buffer, and sets the `'Content-Type'` header to `'application/octet-stream'` if not already set.
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const typedArray = new Uint16Array(10) reply.send(typedArray)})
#### ReadableStream[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#readablestream "Direct link to ReadableStream")
`ReadableStream` will be treated as a node stream mentioned above, the content is considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') reply.header('Content-Type', 'application/octet-stream') reply.send(ReadableStream.from(stream))})
#### Response[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#response "Direct link to Response")
`Response` allows to manage the reply payload, status code and headers in one place. The payload provided inside `Response` is considered to be pre-serialized, so they will be sent unmodified without response validation.
Please be aware when using `Response`, the status code and headers will not directly reflect to `reply.statusCode` and `reply.getHeaders()`. Such behavior is based on `Response` only allow `readonly` status code and headers. The data is not allow to be bi-direction editing, and may confuse when checking the `payload` in `onSend` hooks.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') const readableStream = ReadableStream.from(stream) const response = new Response(readableStream, { status: 200, headers: { 'content-type': 'application/octet-stream' } }) reply.send(response)})
#### Errors[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#errors "Direct link to Errors")
If you pass to _send_ an object that is an instance of _Error_, Fastify will automatically create an error structured as the following:
{ error: String // the HTTP error message code: String // the Fastify error code message: String // the user error message statusCode: Number // the HTTP status code}
You can add custom properties to the Error object, such as `headers`, that will be used to enhance the HTTP response.
> ℹ️ Note: If you are passing an error to `send` and the statusCode is less than 400, Fastify will automatically set it at 500.
Tip: you can simplify errors by using the [`http-errors`](https://npm.im/http-errors)
module or [`@fastify/sensible`](https://github.com/fastify/fastify-sensible)
plugin to generate errors:
fastify.get('/', function (request, reply) { reply.send(httpErrors.Gone())})
To customize the JSON error output you can do it by:
* setting a response JSON schema for the status code you need
* add the additional properties to the `Error` instance
Notice that if the returned status code is not in the response schema list, the default behavior will be applied.
fastify.get('/', { schema: { response: { 501: { type: 'object', properties: { statusCode: { type: 'number' }, code: { type: 'string' }, error: { type: 'string' }, message: { type: 'string' }, time: { type: 'string' } } } } }}, function (request, reply) { const error = new Error('This endpoint has not been implemented') error.time = 'it will be implemented in two weeks' reply.code(501).send(error)})
If you want to customize error handling, check out [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
API.
> ℹ️ Note: you are responsible for logging when customizing the error handler.
API:
fastify.setErrorHandler(function (error, request, reply) { request.log.warn(error) const statusCode = error.statusCode >= 400 ? error.statusCode : 500 reply .code(statusCode) .type('text/plain') .send(statusCode >= 500 ? 'Internal server error' : error.message)})
Beware that calling `reply.send(error)` in your custom error handler will send the error to the default error handler. Check out the [Reply Lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#reply-lifecycle)
for more information.
The not found errors generated by the router will use the [`setNotFoundHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#setnotfoundhandler)
API:
fastify.setNotFoundHandler(function (request, reply) { reply .code(404) .type('text/plain') .send('a custom not found')})
#### Type of the final payload[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#type-of-the-final-payload "Direct link to Type of the final payload")
The type of the sent payload (after serialization and going through any [`onSend` hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onsend)
) must be one of the following types, otherwise, an error will be thrown:
* `string`
* `Buffer`
* `stream`
* `undefined`
* `null`
#### Async-Await and Promises[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#async-await-and-promises "Direct link to Async-Await and Promises")
Fastify natively handles promises and supports async-await.
_Note that in the following examples we are not using reply.send._
const { promisify } = require('node:util')const delay = promisify(setTimeout)fastify.get('/promises', options, function (request, reply) { return delay(200).then(() => { return { hello: 'world' }})})fastify.get('/async-await', options, async function (request, reply) { await delay(200) return { hello: 'world' }})
Rejected promises default to a `500` HTTP status code. Reject the promise, or `throw` in an `async function`, with an object that has `statusCode` (or `status`) and `message` properties to modify the reply.
fastify.get('/teapot', async function (request, reply) { const err = new Error() err.statusCode = 418 err.message = 'short and stout' throw err})fastify.get('/botnet', async function (request, reply) { throw { statusCode: 418, message: 'short and stout' } // will return to the client the same json})
If you want to know more please review [Routes#async-await](https://fastify.dev/docs/v5.4.x/Reference/Routes/#async-await)
.
### .then(fulfilled, rejected)[](https://fastify.dev/docs/v5.4.x/Reference/Reply/#thenfulfilled-rejected "Direct link to .then(fulfilled, rejected)")
As the name suggests, a `Reply` object can be awaited upon, i.e. `await reply` will wait until the reply is sent. The `await` syntax calls the `reply.then()`.
`reply.then(fulfilled, rejected)` accepts two parameters:
* `fulfilled` will be called when a response has been fully sent,
* `rejected` will be called if the underlying stream had an error, e.g. the socket has been destroyed.
For more details, see:
* [https://github.com/fastify/fastify/issues/1864](https://github.com/fastify/fastify/issues/1864)
for the discussion about this feature
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Promise/then](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
for the signature
* [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.4.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.4.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.4.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.4.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headerkey-value)
* [set-cookie](https://fastify.dev/docs/v5.4.x/Reference/Reply/#set-cookie)
* [.headers(object)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#redirectdest-code-)
* [.callNotFound()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype)
* [.serializer(func)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.4.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.4.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.4.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#senddata)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#thenfulfilled-rejected)
---
# Hooks | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Hooks/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Hooks[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#hooks "Direct link to Hooks")
----------------------------------------------------------------------------------------
Hooks are registered with the `fastify.addHook` method and allow you to listen to specific events in the application or request/response lifecycle. You have to register a hook before the event is triggered, otherwise, the event is lost.
By using hooks you can interact directly with the lifecycle of Fastify. There are Request/Reply hooks and application hooks:
* [Request/Reply Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#diagnostics-channel-hooks)
> 🛈 Note: The `done` callback is not available when using `async`/`await` or returning a `Promise`. If you do invoke a `done` callback in this situation unexpected behavior may occur, e.g. duplicate invocation of handlers.
Request/Reply Hooks[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#requestreply-hooks "Direct link to Request/Reply Hooks")
---------------------------------------------------------------------------------------------------------------------------------
[Request](https://fastify.dev/docs/v5.3.x/Reference/Request/)
and [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/)
are the core Fastify objects.
`done` is the function to continue with the [lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/)
.
It is easy to understand where each hook is executed by looking at the [lifecycle page](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/)
.
Hooks are affected by Fastify's encapsulation, and can thus be applied to selected routes. See the [Scopes](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#scope)
section for more information.
There are eight different hooks that you can use in Request/Reply _(in order of execution)_:
### onRequest[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest "Direct link to onRequest")
fastify.addHook('onRequest', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequest', async (request, reply) => { // Some code await asyncMethod()})
> 🛈 Note: In the [onRequest](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
> hook.
### preParsing[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing "Direct link to preParsing")
If you are using the `preParsing` hook, you can transform the request payload stream before it is parsed. It receives the request and reply objects as other hooks, and a stream with the current request payload.
If it returns a value (via `return` or via the callback function), it must return a stream.
For instance, you can decompress the request body:
fastify.addHook('preParsing', (request, reply, payload, done) => { // Some code done(null, newPayload)})
Or `async/await`:
fastify.addHook('preParsing', async (request, reply, payload) => { // Some code await asyncMethod() return newPayload})
> 🛈 Note: In the [preParsing](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
> hook.
> 🛈 Note: You should also add a `receivedEncodedLength` property to the returned stream. This property is used to correctly match the request payload with the `Content-Length` header value. Ideally, this property should be updated on each received chunk.
> 🛈 Note: The size of the returned stream is checked to not exceed the limit set in [`bodyLimit`](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit)
> option.
### preValidation[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation "Direct link to preValidation")
If you are using the `preValidation` hook, you can change the payload before it is validated. For example:
fastify.addHook('preValidation', (request, reply, done) => { request.body = { ...request.body, importantKey: 'randomString' } done()})
Or `async/await`:
fastify.addHook('preValidation', async (request, reply) => { const importantKey = await generateRandomString() request.body = { ...request.body, importantKey }})
### preHandler[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prehandler "Direct link to preHandler")
The `preHandler` hook allows you to specify a function that is executed before a routes's handler.
fastify.addHook('preHandler', (request, reply, done) => { // some code done()})
Or `async/await`:
fastify.addHook('preHandler', async (request, reply) => { // Some code await asyncMethod()})
### preSerialization[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preserialization "Direct link to preSerialization")
If you are using the `preSerialization` hook, you can change (or replace) the payload before it is serialized. For example:
fastify.addHook('preSerialization', (request, reply, payload, done) => { const err = null const newPayload = { wrapped: payload } done(err, newPayload)})
Or `async/await`:
fastify.addHook('preSerialization', async (request, reply, payload) => { return { wrapped: payload }})
> 🛈 Note: The hook is NOT called if the payload is a `string`, a `Buffer`, a `stream`, or `null`.
### onError[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onerror "Direct link to onError")
fastify.addHook('onError', (request, reply, error, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onError', async (request, reply, error) => { // Useful for custom error logging // You should not use this hook to update the error})
This hook is useful if you need to do some custom error logging or add some specific header in case of error.
It is not intended for changing the error, and calling `reply.send` will throw an exception.
This hook will be executed only after the [Custom Error Handler set by `setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
has been executed, and only if the custom error handler sends an error back to the user _(Note that the default error handler always sends the error back to the user)_.
> 🛈 Note: Unlike the other hooks, passing an error to the `done` function is not supported.
### onSend[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onsend "Direct link to onSend")
If you are using the `onSend` hook, you can change the payload. For example:
fastify.addHook('onSend', (request, reply, payload, done) => { const err = null; const newPayload = payload.replace('some-text', 'some-new-text') done(err, newPayload)})
Or `async/await`:
fastify.addHook('onSend', async (request, reply, payload) => { const newPayload = payload.replace('some-text', 'some-new-text') return newPayload})
You can also clear the payload to send a response with an empty body by replacing the payload with `null`:
fastify.addHook('onSend', (request, reply, payload, done) => { reply.code(304) const newPayload = null done(null, newPayload)})
> You can also send an empty body by replacing the payload with the empty string `''`, but be aware that this will cause the `Content-Length` header to be set to `0`, whereas the `Content-Length` header will not be set if the payload is `null`.
> 🛈 Note: If you change the payload, you may only change it to a `string`, a `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
### onResponse[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onresponse "Direct link to onResponse")
fastify.addHook('onResponse', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onResponse', async (request, reply) => { // Some code await asyncMethod()})
The `onResponse` hook is executed when a response has been sent, so you will not be able to send more data to the client. It can however be useful for sending data to external services, for example, to gather statistics.
> 🛈 Note: Setting `disableRequestLogging` to `true` will disable any error log inside the `onResponse` hook. In this case use `try - catch` to log errors.
### onTimeout[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#ontimeout "Direct link to onTimeout")
fastify.addHook('onTimeout', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onTimeout', async (request, reply) => { // Some code await asyncMethod()})
`onTimeout` is useful if you need to monitor the request timed out in your service (if the `connectionTimeout` property is set on the Fastify instance). The `onTimeout` hook is executed when a request is timed out and the HTTP socket has been hung up. Therefore, you will not be able to send data to the client.
### onRequestAbort[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequestabort "Direct link to onRequestAbort")
fastify.addHook('onRequestAbort', (request, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequestAbort', async (request) => { // Some code await asyncMethod()})
The `onRequestAbort` hook is executed when a client closes the connection before the entire request has been processed. Therefore, you will not be able to send data to the client.
> 🛈 Note: Client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](https://fastify.dev/docs/v5.3.x/Guides/Detecting-When-Clients-Abort/)
### Manage Errors from a hook[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#manage-errors-from-a-hook "Direct link to Manage Errors from a hook")
If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
fastify.addHook('onRequest', (request, reply, done) => { done(new Error('Some error'))})
If you want to pass a custom error code to the user, just use `reply.code()`:
fastify.addHook('preHandler', (request, reply, done) => { reply.code(400) done(new Error('Some error'))})
_The error will be handled by [`Reply`](https://fastify.dev/docs/v5.3.x/Reference/Reply/#errors)
._
Or if you're using `async/await` you can just throw an error:
fastify.addHook('onRequest', async (request, reply) => { throw new Error('Some error')})
### Respond to a request from a hook[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#respond-to-a-request-from-a-hook "Direct link to Respond to a request from a hook")
If needed, you can respond to a request before you reach the route handler, for example when implementing an authentication hook. Replying from a hook implies that the hook chain is **stopped** and the rest of the hooks and handlers are not executed. If the hook is using the callback approach, i.e. it is not an `async` function or it returns a `Promise`, it is as simple as calling `reply.send()` and avoiding calling the callback. If the hook is `async`, `reply.send()` **must** be called _before_ the function returns or the promise resolves, otherwise, the request will proceed. When `reply.send()` is called outside of the promise chain, it is important to `return reply` otherwise the request will be executed twice.
It is important to **not mix callbacks and `async`/`Promise`**, otherwise the hook chain will be executed twice.
If you are using `onRequest` or `preHandler` use `reply.send`.
fastify.addHook('onRequest', (request, reply, done) => { reply.send('Early response')})// Works with async functions toofastify.addHook('preHandler', async (request, reply) => { setTimeout(() => { reply.send({ hello: 'from prehandler' }) }) return reply // mandatory, so the request is not executed further// Commenting the line above will allow the hooks to continue and fail with FST_ERR_REP_ALREADY_SENT})
If you want to respond with a stream, you should avoid using an `async` function for the hook. If you must use an `async` function, your code will need to follow the pattern in [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275)
.
fastify.addHook('onRequest', (request, reply, done) => { const stream = fs.createReadStream('some-file', 'utf8') reply.send(stream)})
If you are sending a response without `await` on it, make sure to always `return reply`:
fastify.addHook('preHandler', async (request, reply) => { setImmediate(() => { reply.send('hello') }) // This is needed to signal the handler to wait for a response // to be sent outside of the promise chain return reply})fastify.addHook('preHandler', async (request, reply) => { // the @fastify/static plugin will send a file asynchronously, // so we should return reply reply.sendFile('myfile') return reply})
Application Hooks[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#application-hooks "Direct link to Application Hooks")
----------------------------------------------------------------------------------------------------------------------------
You can hook into the application-lifecycle as well.
* [onReady](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onregister)
### onReady[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onready "Direct link to onReady")
Triggered before the server starts listening for requests and when `.ready()` is invoked. It cannot change the routes or add new hooks. Registered hook functions are executed serially. Only after all `onReady` hook functions have completed will the server start listening for requests. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
// callback stylefastify.addHook('onReady', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onReady', async function () { // Some async code await loadCacheFromDatabase()})
### onListen[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onlisten "Direct link to onListen")
Triggered when the server starts listening for requests. The hooks run one after another. If a hook function causes an error, it is logged and ignored, allowing the queue of hooks to continue. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
This is an alternative to `fastify.server.on('listening', () => {})`.
// callback stylefastify.addHook('onListen', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onListen', async function () { // Some async code})
> 🛈 Note: This hook will not run when the server is started using fastify.inject()`or`fastify.ready()\`.
### onClose[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose "Direct link to onClose")
Triggered when `fastify.close()` is invoked to stop the server, after all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
need a "shutdown" event, for example, to close an open connection to a database.
The hook function takes the Fastify instance as a first argument, and a `done` callback for synchronous hook functions.
// callback stylefastify.addHook('onClose', (instance, done) => { // Some code done()})// or async/await stylefastify.addHook('onClose', async (instance) => { // Some async code await closeDatabaseConnections()})
### preClose[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preclose "Direct link to preClose")
Triggered when `fastify.close()` is invoked to stop the server, before all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
have set up some state attached to the HTTP server that would prevent the server to close. _It is unlikely you will need to use this hook_, use the [`onClose`](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose)
for the most common case.
// callback stylefastify.addHook('preClose', (done) => { // Some code done()})// or async/await stylefastify.addHook('preClose', async () => { // Some async code await removeSomeServerState()})
### onRoute[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onroute "Direct link to onRoute")
Triggered when a new route is registered. Listeners are passed a [`routeOptions`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-options)
object as the sole parameter. The interface is synchronous, and, as such, the listeners are not passed a callback. This hook is encapsulated.
fastify.addHook('onRoute', (routeOptions) => { //Some code routeOptions.method routeOptions.schema routeOptions.url // the complete URL of the route, it will include the prefix if any routeOptions.path // `url` alias routeOptions.routePath // the URL of the route without the prefix routeOptions.bodyLimit routeOptions.logLevel routeOptions.logSerializers routeOptions.prefix})
If you are authoring a plugin and you need to customize application routes, like modifying the options or adding new route hooks, this is the right place.
fastify.addHook('onRoute', (routeOptions) => { function onPreSerialization(request, reply, payload, done) { // Your code done(null, payload) } // preSerialization can be an array or undefined routeOptions.preSerialization = [...(routeOptions.preSerialization || []), onPreSerialization]})
To add more routes within an onRoute hook, the routes must be tagged correctly. The hook will run into an infinite loop if not tagged. The recommended approach is shown below.
const kRouteAlreadyProcessed = Symbol('route-already-processed')fastify.addHook('onRoute', function (routeOptions) { const { url, method } = routeOptions const isAlreadyProcessed = (routeOptions.custom && routeOptions.custom[kRouteAlreadyProcessed]) || false if (!isAlreadyProcessed) { this.route({ url, method, custom: { [kRouteAlreadyProcessed]: true }, handler: () => {} }) }})
For more details, see this [issue](https://github.com/fastify/fastify/issues/4319)
.
### onRegister[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onregister "Direct link to onRegister")
Triggered when a new plugin is registered and a new encapsulation context is created. The hook will be executed **before** the registered code.
This hook can be useful if you are developing a plugin that needs to know when a plugin context is formed, and you want to operate in that specific context, thus this hook is encapsulated.
> 🛈 Note: This hook will not be called if a plugin is wrapped inside [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
> .
fastify.decorate('data', [])fastify.register(async (instance, opts) => { instance.data.push('hello') console.log(instance.data) // ['hello'] instance.register(async (instance, opts) => { instance.data.push('world') console.log(instance.data) // ['hello', 'world'] }, { prefix: '/hola' })}, { prefix: '/ciao' })fastify.register(async (instance, opts) => { console.log(instance.data) // []}, { prefix: '/hello' })fastify.addHook('onRegister', (instance, opts) => { // Create a new array from the old one // but without keeping the reference // allowing the user to have encapsulated // instances of the `data` property instance.data = instance.data.slice() // the options of the new registered instance console.log(opts.prefix)})
Scope[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#scope "Direct link to Scope")
----------------------------------------------------------------------------------------
Except for [onClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose)
, all hooks are encapsulated. This means that you can decide where your hooks should run by using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.3.x/Guides/Plugins-Guide/)
. If you pass a function, that function is bound to the right Fastify context and from there you have full access to the Fastify API.
fastify.addHook('onRequest', function (request, reply, done) { const self = this // Fastify context done()})
Note that the Fastify context in each hook is the same as the plugin where the route was registered, for example:
fastify.addHook('onRequest', async function (req, reply) { if (req.raw.url === '/nested') { assert.strictEqual(this.foo, 'bar') } else { assert.strictEqual(this.foo, undefined) }})fastify.get('/', async function (req, reply) { assert.strictEqual(this.foo, undefined) return { hello: 'world' }})fastify.register(async function plugin (fastify, opts) { fastify.decorate('foo', 'bar') fastify.get('/nested', async function (req, reply) { assert.strictEqual(this.foo, 'bar') return { hello: 'world' } })})
Warn: if you declare the function with an [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
, the `this` will not be Fastify, but the one of the current scope.
Route level hooks[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-level-hooks "Direct link to Route level hooks")
----------------------------------------------------------------------------------------------------------------------------
You can declare one or more custom lifecycle hooks ([onRequest](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
, [onResponse](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onresponse)
, [preParsing](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
, [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
, [preHandler](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prehandler)
, [preSerialization](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preserialization)
, [onSend](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onsend)
, [onTimeout](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#ontimeout)
, and [onError](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onerror)
) hook(s) that will be **unique** for the route. If you do so, those hooks are always executed as the last hook in their category.
This can be useful if you need to implement authentication, where the [preParsing](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
or [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
hooks are exactly what you need. Multiple route-level hooks can also be specified as an array.
fastify.addHook('onRequest', (request, reply, done) => { // Your code done()})fastify.addHook('onResponse', (request, reply, done) => { // your code done()})fastify.addHook('preParsing', (request, reply, done) => { // Your code done()})fastify.addHook('preValidation', (request, reply, done) => { // Your code done()})fastify.addHook('preHandler', (request, reply, done) => { // Your code done()})fastify.addHook('preSerialization', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onSend', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onTimeout', (request, reply, done) => { // Your code done()})fastify.addHook('onError', (request, reply, error, done) => { // Your code done()})fastify.route({ method: 'GET', url: '/', schema: { ... }, onRequest: function (request, reply, done) { // This hook will always be executed after the shared `onRequest` hooks done() }, // // Example with an async hook. All hooks support this syntax // // onRequest: async function (request, reply) { // // This hook will always be executed after the shared `onRequest` hooks // await ... // } onResponse: function (request, reply, done) { // this hook will always be executed after the shared `onResponse` hooks done() }, preParsing: function (request, reply, done) { // This hook will always be executed after the shared `preParsing` hooks done() }, preValidation: function (request, reply, done) { // This hook will always be executed after the shared `preValidation` hooks done() }, preHandler: function (request, reply, done) { // This hook will always be executed after the shared `preHandler` hooks done() }, // // Example with an array. All hooks support this syntax. // // preHandler: [function (request, reply, done) { // // This hook will always be executed after the shared `preHandler` hooks // done() // }], preSerialization: (request, reply, payload, done) => { // This hook will always be executed after the shared `preSerialization` hooks done(null, payload) }, onSend: (request, reply, payload, done) => { // This hook will always be executed after the shared `onSend` hooks done(null, payload) }, onTimeout: (request, reply, done) => { // This hook will always be executed after the shared `onTimeout` hooks done() }, onError: (request, reply, error, done) => { // This hook will always be executed after the shared `onError` hooks done() }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})
> 🛈 Note: Both options also accept an array of functions.
Using Hooks to Inject Custom Properties[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#using-hooks-to-inject-custom-properties "Direct link to Using Hooks to Inject Custom Properties")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
You can use a hook to inject custom properties into incoming requests. This is useful for reusing processed data from hooks in controllers.
A very common use case is, for example, checking user authentication based on their token and then storing their recovered data into the [Request](https://fastify.dev/docs/v5.3.x/Reference/Request/)
instance. This way, your controllers can read it easily with `request.authenticatedUser` or whatever you want to call it. That's how it might look like:
fastify.addHook('preParsing', async (request) => { request.authenticatedUser = { id: 42, name: 'Jane Doe', role: 'admin' }})fastify.get('/me/is-admin', async function (req, reply) { return { isAdmin: req.authenticatedUser?.role === 'admin' || false }})
Note that `.authenticatedUser` could actually be any property name chosen by yourself. Using your own custom property prevents you from mutating existing properties, which would be a dangerous and destructive operation. So be careful and make sure your property is entirely new, also using this approach only for very specific and small cases like this example.
Regarding TypeScript in this example, you'd need to update the `FastifyRequest` core interface to include your new property typing (for more about it, see [TypeScript](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/)
page), like:
interface AuthenticatedUser { /* ... */ }declare module 'fastify' { export interface FastifyRequest { authenticatedUser?: AuthenticatedUser; }}
Although this is a very pragmatic approach, if you're trying to do something more complex that changes these core objects, then consider creating a custom [Plugin](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
instead.
Diagnostics Channel Hooks[](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#diagnostics-channel-hooks "Direct link to Diagnostics Channel Hooks")
----------------------------------------------------------------------------------------------------------------------------------------------------
One [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
publish event, `'fastify.initialization'`, happens at initialization time. The Fastify instance is passed into the hook as a property of the object passed in. At this point, the instance can be interacted with to add hooks, plugins, routes, or any other sort of modification.
For example, a tracing package might do something like the following (which is, of course, a simplification). This would be in a file loaded in the initialization of the tracking package, in the typical "require instrumentation tools first" fashion.
const tracer = /* retrieved from elsewhere in the package */const dc = require('node:diagnostics_channel')const channel = dc.channel('fastify.initialization')const spans = new WeakMap()channel.subscribe(function ({ fastify }) { fastify.addHook('onRequest', (request, reply, done) => { const span = tracer.startSpan('fastify.request.handler') spans.set(request, span) done() }) fastify.addHook('onResponse', (request, reply, done) => { const span = spans.get(request) span.finish() done() })})
> 🛈 Note: The TracingChannel class API is currently experimental and may undergo breaking changes even in semver-patch releases of Node.js.
Five other events are published on a per-request basis following the [Tracing Channel](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel)
nomenclature. The list of the channel names and the event they receive is:
* `tracing:fastify.request.handler:start`: Always fires
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:end`: Always fires
* `{ request: Request, reply: Reply, route: { url, method }, async: Bool }`
* `tracing:fastify.request.handler:asyncStart`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:asyncEnd`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:error`: Fires when an error occurs
* `{ request: Request, reply: Reply, route: { url, method }, error: Error }`
The object instance remains the same for all events associated with a given request. All payloads include a `request` and `reply` property which are an instance of Fastify's `Request` and `Reply` instances. They also include a `route` property which is an object with the matched `url` pattern (e.g. `/collection/:id`) and the `method` HTTP method (e.g. `GET`). The `:start` and `:end` events always fire for requests. If a request handler is an `async` function or one that returns a `Promise` then the `:asyncStart` and `:asyncEnd` events also fire. Finally, the `:error` event contains an `error` property associated with the request's failure.
These events can be received like so:
const dc = require('node:diagnostics_channel')const channel = dc.channel('tracing:fastify.request.handler:start')channel.subscribe((msg) => { console.log(msg.request, msg.reply)})
* [Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#hooks)
* [Request/Reply Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#diagnostics-channel-hooks)
---
# Routes | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Routes/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Routes[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes "Direct link to Routes")
--------------------------------------------------------------------------------------------
The route methods configure the endpoints of the application. Routes can be declared using the shorthand method or the full declaration.
* [Full declaration](https://fastify.dev/docs/v5.4.x/Reference/Routes/#full-declaration)
* [Routes options](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-options)
* [Shorthand declaration](https://fastify.dev/docs/v5.4.x/Reference/Routes/#shorthand-declaration)
* [Url building](https://fastify.dev/docs/v5.4.x/Reference/Routes/#url-building)
* [Async Await](https://fastify.dev/docs/v5.4.x/Reference/Routes/#async-await)
* [Promise resolution](https://fastify.dev/docs/v5.4.x/Reference/Routes/#promise-resolution)
* [Route Prefixing](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing)
* [Handling of / route inside prefixed plugins](https://fastify.dev/docs/v5.4.x/Reference/Routes/#handling-of--route-inside-prefixed-plugins)
* [Custom Log Level](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-level)
* [Custom Log Serializer](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-serializer)
* [Config](https://fastify.dev/docs/v5.4.x/Reference/Routes/#config)
* [Constraints](https://fastify.dev/docs/v5.4.x/Reference/Routes/#constraints)
* [Version Constraints](https://fastify.dev/docs/v5.4.x/Reference/Routes/#version-constraints)
* [Host Constraints](https://fastify.dev/docs/v5.4.x/Reference/Routes/#host-constraints)
### Full declaration[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#full-declaration "Direct link to Full declaration")
fastify.route(options)
### Routes options[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-options "Direct link to Routes options")
* `method`: currently it supports `GET`, `HEAD`, `TRACE`, `DELETE`, `OPTIONS`, `PATCH`, `PUT` and `POST`. To accept more methods, the [`addHttpMethod`](https://fastify.dev/docs/v5.4.x/Reference/Server/#addHttpMethod)
must be used. It could also be an array of methods.
* `url`: the path of the URL to match this route (alias: `path`).
* `schema`: an object containing the schemas for the request and response. They need to be in [JSON Schema](https://json-schema.org/)
format, check [here](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/)
for more info.
* `body`: validates the body of the request if it is a POST, PUT, PATCH, TRACE, SEARCH, PROPFIND, PROPPATCH or LOCK method.
* `querystring` or `query`: validates the querystring. This can be a complete JSON Schema object, with the property `type` of `object` and `properties` object of parameters, or simply the values of what would be contained in the `properties` object as shown below.
* `params`: validates the params.
* `response`: filter and generate a schema for the response, setting a schema allows us to have 10-20% more throughput.
* `exposeHeadRoute`: creates a sibling `HEAD` route for any `GET` routes. Defaults to the value of [`exposeHeadRoutes`](https://fastify.dev/docs/v5.4.x/Reference/Server/#exposeHeadRoutes)
instance option. If you want a custom `HEAD` handler without disabling this option, make sure to define it before the `GET` route.
* `attachValidation`: attach `validationError` to request, if there is a schema validation error, instead of sending the error to the error handler. The default [error format](https://ajv.js.org/api.html#error-objects)
is the Ajv one.
* `onRequest(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onrequest)
called as soon as a request is received, it could also be an array of functions.
* `preParsing(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
called before parsing the request, it could also be an array of functions.
* `preValidation(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prevalidation)
called after the shared `preValidation` hooks, useful if you need to perform authentication at route level for example, it could also be an array of functions.
* `preHandler(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#prehandler)
called just before the request handler, it could also be an array of functions.
* `preSerialization(request, reply, payload, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preserialization)
called just before the serialization, it could also be an array of functions.
* `onSend(request, reply, payload, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-hooks)
called right before a response is sent, it could also be an array of functions.
* `onResponse(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onresponse)
called when a response has been sent, so you will not be able to send more data to the client. It could also be an array of functions.
* `onTimeout(request, reply, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#ontimeout)
called when a request is timed out and the HTTP socket has been hung up.
* `onError(request, reply, error, done)`: a [function](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#onerror)
called when an Error is thrown or sent to the client by the route handler.
* `handler(request, reply)`: the function that will handle this request. The [Fastify server](https://fastify.dev/docs/v5.4.x/Reference/Server/)
will be bound to `this` when the handler is called. Note: using an arrow function will break the binding of `this`.
* `errorHandler(error, request, reply)`: a custom error handler for the scope of the request. Overrides the default error global handler, and anything set by [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
, for requests to the route. To access the default handler, you can access `instance.errorHandler`. Note that this will point to fastify's default `errorHandler` only if a plugin hasn't overridden it already.
* `childLoggerFactory(logger, binding, opts, rawReq)`: a custom factory function that will be called to produce a child logger instance for every request. See [`childLoggerFactory`](https://fastify.dev/docs/v5.4.x/Reference/Server/#childloggerfactory)
for more info. Overrides the default logger factory, and anything set by [`setChildLoggerFactory`](https://fastify.dev/docs/v5.4.x/Reference/Server/#setchildloggerfactory)
, for requests to the route. To access the default factory, you can access `instance.childLoggerFactory`. Note that this will point to Fastify's default `childLoggerFactory` only if a plugin hasn't overridden it already.
* `validatorCompiler({ schema, method, url, httpPart })`: function that builds schemas for request validations. See the [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schema-validator)
documentation.
* `serializerCompiler({ { schema, method, url, httpStatus, contentType } })`: function that builds schemas for response serialization. See the [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schema-serializer)
documentation.
* `schemaErrorFormatter(errors, dataVar)`: function that formats the errors from the validation compiler. See the [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#error-handling)
documentation. Overrides the global schema error formatter handler, and anything set by `setSchemaErrorFormatter`, for requests to the route.
* `bodyLimit`: prevents the default JSON body parser from parsing request bodies larger than this number of bytes. Must be an integer. You may also set this option globally when first creating the Fastify instance with `fastify(options)`. Defaults to `1048576` (1 MiB).
* `logLevel`: set log level for this route. See below.
* `logSerializers`: set serializers to log for this route.
* `config`: object used to store custom configuration.
* `version`: a [semver](https://semver.org/)
compatible string that defined the version of the endpoint. [Example](https://fastify.dev/docs/v5.4.x/Reference/Routes/#version-constraints)
.
* `constraints`: defines route restrictions based on request properties or values, enabling customized matching using [find-my-way](https://github.com/delvedor/find-my-way)
constraints. Includes built-in `version` and `host` constraints, with support for custom constraint strategies.
* `prefixTrailingSlash`: string used to determine how to handle passing `/` as a route with a prefix.
* `both` (default): Will register both `/prefix` and `/prefix/`.
* `slash`: Will register only `/prefix/`.
* `no-slash`: Will register only `/prefix`.
Note: this option does not override `ignoreTrailingSlash` in [Server](https://fastify.dev/docs/v5.4.x/Reference/Server/)
configuration.
* `request` is defined in [Request](https://fastify.dev/docs/v5.4.x/Reference/Request/)
.
* `reply` is defined in [Reply](https://fastify.dev/docs/v5.4.x/Reference/Reply/)
.
> ℹ️ Note: The documentation for `onRequest`, `preParsing`, `preValidation`, `preHandler`, `preSerialization`, `onSend`, and `onResponse` is detailed in [Hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/)
> . To send a response before the request is handled by the `handler`, see [Respond to a request from a hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
> .
Example:
fastify.route({ method: 'GET', url: '/', schema: { querystring: { type: 'object', properties: { name: { type: 'string' }, excitement: { type: 'integer' } } }, response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})
### Shorthand declaration[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#shorthand-declaration "Direct link to Shorthand declaration")
The above route declaration is more _Hapi_\-like, but if you prefer an _Express/Restify_ approach, we support it as well:
`fastify.get(path, [options], handler)`
`fastify.head(path, [options], handler)`
`fastify.post(path, [options], handler)`
`fastify.put(path, [options], handler)`
`fastify.delete(path, [options], handler)`
`fastify.options(path, [options], handler)`
`fastify.patch(path, [options], handler)`
Example:
const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }}fastify.get('/', opts, (request, reply) => { reply.send({ hello: 'world' })})
`fastify.all(path, [options], handler)` will add the same handler to all the supported methods.
The handler may also be supplied via the `options` object:
const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }, handler: function (request, reply) { reply.send({ hello: 'world' }) }}fastify.get('/', opts)
> ℹ️ Note: Specifying the handler in both `options` and as the third parameter to the shortcut method throws a duplicate `handler` error.
### Url building[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#url-building "Direct link to Url building")
Fastify supports both static and dynamic URLs.
To register a **parametric** path, use a _colon_ before the parameter name. For **wildcard**, use a _star_. Static routes are always checked before parametric and wildcard routes.
// parametricfastify.get('/example/:userId', function (request, reply) { // curl ${app-url}/example/12345 // userId === '12345' const { userId } = request.params; // your code here})fastify.get('/example/:userId/:secretToken', function (request, reply) { // curl ${app-url}/example/12345/abc.zHi // userId === '12345' // secretToken === 'abc.zHi' const { userId, secretToken } = request.params; // your code here})// wildcardfastify.get('/example/*', function (request, reply) {})
Regular expression routes are supported, but slashes must be escaped. Take note that RegExp is also very expensive in terms of performance!
// parametric with regexpfastify.get('/example/:file(^\\d+).png', function (request, reply) { // curl ${app-url}/example/12345.png // file === '12345' const { file } = request.params; // your code here})
It is possible to define more than one parameter within the same couple of slash ("/"). Such as:
fastify.get('/example/near/:lat-:lng/radius/:r', function (request, reply) { // curl ${app-url}/example/near/15°N-30°E/radius/20 // lat === "15°N" // lng === "30°E" // r ==="20" const { lat, lng, r } = request.params; // your code here})
_Remember in this case to use the dash ("-") as parameters separator._
Finally, it is possible to have multiple parameters with RegExp:
fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', function (request, reply) { // curl ${app-url}/example/at/08h24m // hour === "08" // minute === "24" const { hour, minute } = request.params; // your code here})
In this case as parameter separator it is possible to use whatever character is not matched by the regular expression.
The last parameter can be made optional by adding a question mark ("?") to the end of the parameter name.
fastify.get('/example/posts/:id?', function (request, reply) { const { id } = request.params; // your code here})
In this case, `/example/posts` and `/example/posts/1` are both valid. The optional param will be `undefined` if not specified.
Having a route with multiple parameters may negatively affect performance. Prefer a single parameter approach, especially on routes that are on the hot path of your application. For more details, see [find-my-way](https://github.com/delvedor/find-my-way)
.
To include a colon in a path without declaring a parameter, use a double colon. For example:
fastify.post('/name::verb') // will be interpreted as /name:verb
### Async Await[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#async-await "Direct link to Async Await")
Are you an `async/await` user? We have you covered!
fastify.get('/', options, async function (request, reply) { const data = await getData() const processed = await processData(data) return processed})
As shown, `reply.send` is not called to send data back to the user. Simply return the body and you are done!
If needed, you can also send data back with `reply.send`. In this case, do not forget to `return reply` or `await reply` in your `async` handler to avoid race conditions.
fastify.get('/', options, async function (request, reply) { const data = await getData() const processed = await processData(data) return reply.send(processed)})
If the route is wrapping a callback-based API that will call `reply.send()` outside of the promise chain, it is possible to `await reply`:
fastify.get('/', options, async function (request, reply) { setImmediate(() => { reply.send({ hello: 'world' }) }) await reply})
Returning reply also works:
fastify.get('/', options, async function (request, reply) { setImmediate(() => { reply.send({ hello: 'world' }) }) return reply})
> ⚠ Warning:
>
> * When using both `return value` and `reply.send(value)`, the first one takes precedence, the second is discarded, and a _warn_ log is emitted.
> * Calling `reply.send()` outside of the promise is possible but requires special attention. See [promise-resolution](https://fastify.dev/docs/v5.4.x/Reference/Routes/#promise-resolution)
> .
> * `undefined` cannot be returned. See [promise-resolution](https://fastify.dev/docs/v5.4.x/Reference/Routes/#promise-resolution)
> .
### Promise resolution[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#promise-resolution "Direct link to Promise resolution")
If the handler is an `async` function or returns a promise, be aware of the special behavior to support callback and promise control-flow. When the handler's promise resolves, the reply is automatically sent with its value unless you explicitly await or return `reply` in the handler.
1. If using `async/await` or promises but responding with `reply.send`:
* **Do** `return reply` / `await reply`.
* **Do not** forget to call `reply.send`.
2. If using `async/await` or promises:
* **Do not** use `reply.send`.
* **Do** return the value to send.
This approach supports both `callback-style` and `async-await` with minimal trade-off. However, it is recommended to use only one style for consistent error handling within your application.
> ℹ️ Note: Every async function returns a promise by itself.
### Route Prefixing[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing "Direct link to Route Prefixing")
Sometimes maintaining multiple versions of the same API is necessary. A common approach is to prefix routes with the API version number, e.g., `/v1/user`. Fastify offers a fast and smart way to create different versions of the same API without changing all the route names by hand, called _route prefixing_. Here is how it works:
// server.jsconst fastify = require('fastify')()fastify.register(require('./routes/v1/users'), { prefix: '/v1' })fastify.register(require('./routes/v2/users'), { prefix: '/v2' })fastify.listen({ port: 3000 })
// routes/v1/users.jsmodule.exports = function (fastify, opts, done) { fastify.get('/user', handler_v1) done()}
// routes/v2/users.jsmodule.exports = function (fastify, opts, done) { fastify.get('/user', handler_v2) done()}
Fastify will not complain about using the same name for two different routes because it handles the prefix automatically at compilation time. This ensures performance is not affected.
Now clients will have access to the following routes:
* `/v1/user`
* `/v2/user`
This can be done multiple times and works for nested `register`. Route parameters are also supported.
To use a prefix for all routes, place them inside a plugin:
const fastify = require('fastify')()const route = { method: 'POST', url: '/login', handler: () => {}, schema: {},}fastify.register(function (app, _, done) { app.get('/users', () => {}) app.route(route) done()}, { prefix: '/v1' }) // global route prefixawait fastify.listen({ port: 3000 })
### Route Prefixing and fastify-plugin[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing-and-fastify-plugin "Direct link to Route Prefixing and fastify-plugin")
If using [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
to wrap routes, this option will not work. To make it work, wrap a plugin in a plugin:
const fp = require('fastify-plugin')const routes = require('./lib/routes')module.exports = fp(async function (app, opts) { app.register(routes, { prefix: '/v1', })}, { name: 'my-routes'})
#### Handling of / route inside prefixed plugins[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#handling-of--route-inside-prefixed-plugins "Direct link to Handling of / route inside prefixed plugins")
The `/` route behaves differently based on whether the prefix ends with `/`. For example, with a prefix `/something/`, adding a `/` route matches only `/something/`. With a prefix `/something`, adding a `/` route matches both `/something` and `/something/`.
See the `prefixTrailingSlash` route option above to change this behavior.
### Custom Log Level[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-level "Direct link to Custom Log Level")
Different log levels can be set for routes in Fastify by passing the `logLevel` option to the plugin or route with the desired [value](https://github.com/pinojs/pino/blob/master/docs/api.md#level-string)
.
Be aware that setting `logLevel` at the plugin level also affects [`setNotFoundHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#setnotfoundhandler)
and [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
.
// server.jsconst fastify = require('fastify')({ logger: true })fastify.register(require('./routes/user'), { logLevel: 'warn' })fastify.register(require('./routes/events'), { logLevel: 'debug' })fastify.listen({ port: 3000 })
Or pass it directly to a route:
fastify.get('/', { logLevel: 'warn' }, (request, reply) => { reply.send({ hello: 'world' })})
_Remember that the custom log level applies only to routes, not to the global Fastify Logger, accessible with `fastify.log`._
### Custom Log Serializer[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-serializer "Direct link to Custom Log Serializer")
In some contexts, logging a large object may waste resources. Define custom [`serializers`](https://github.com/pinojs/pino/blob/master/docs/api.md#serializers-object)
and attach them in the appropriate context.
const fastify = require('fastify')({ logger: true })fastify.register(require('./routes/user'), { logSerializers: { user: (value) => `My serializer one - ${value.name}` }})fastify.register(require('./routes/events'), { logSerializers: { user: (value) => `My serializer two - ${value.name} ${value.surname}` }})fastify.listen({ port: 3000 })
Serializers can be inherited by context:
const fastify = Fastify({ logger: { level: 'info', serializers: { user (req) { return { method: req.method, url: req.url, headers: req.headers, host: req.host, remoteAddress: req.ip, remotePort: req.socket.remotePort } } } }})fastify.register(context1, { logSerializers: { user: value => `My serializer father - ${value}` }})async function context1 (fastify, opts) { fastify.get('/', (req, reply) => { req.log.info({ user: 'call father serializer', key: 'another key' }) // shows: { user: 'My serializer father - call father serializer', key: 'another key' } reply.send({}) })}fastify.listen({ port: 3000 })
### Config[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#config "Direct link to Config")
Registering a new handler, you can pass a configuration object to it and retrieve it in the handler.
// server.jsconst fastify = require('fastify')()function handler (req, reply) { reply.send(reply.routeOptions.config.output)}fastify.get('/en', { config: { output: 'hello world!' } }, handler)fastify.get('/it', { config: { output: 'ciao mondo!' } }, handler)fastify.listen({ port: 3000 })
### Constraints[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#constraints "Direct link to Constraints")
Fastify supports constraining routes to match certain requests based on properties like the `Host` header or any other value via [`find-my-way`](https://github.com/delvedor/find-my-way)
constraints. Constraints are specified in the `constraints` property of the route options. Fastify has two built-in constraints: `version` and `host`. Custom constraint strategies can be added to inspect other parts of a request to decide if a route should be executed.
#### Version Constraints[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#version-constraints "Direct link to Version Constraints")
You can provide a `version` key in the `constraints` option to a route. Versioned routes allows multiple handlers to be declared for the same HTTP route path, matched according to the request's `Accept-Version` header. The `Accept-Version` header value should follow the [semver](https://semver.org/)
specification, and routes should be declared with exact semver versions for matching.
Fastify will require a request `Accept-Version` header to be set if the route has a version set, and will prefer a versioned route to a non-versioned route for the same path. Advanced version ranges and pre-releases currently are not supported.
_Be aware that using this feature will cause a degradation of the overall performances of the router._
fastify.route({ method: 'GET', url: '/', constraints: { version: '1.2.0' }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})fastify.inject({ method: 'GET', url: '/', headers: { 'Accept-Version': '1.x' // it could also be '1.2.0' or '1.2.x' }}, (err, res) => { // { hello: 'world' }})
> ⚠ Warning: Set a [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary)
> header in responses with the value used for versioning (e.g., `'Accept-Version'`) to prevent cache poisoning attacks. This can also be configured in a Proxy/CDN.
>
> const append = require('vary').appendfastify.addHook('onSend', (req, reply, payload, done) => { if (req.headers['accept-version']) { // or the custom header being used let value = reply.getHeader('Vary') || '' const header = Array.isArray(value) ? value.join(', ') : String(value) if ((value = append(header, 'Accept-Version'))) { // or the custom header being used reply.header('Vary', value) } } done()})
If multiple versions with the same major or minor are declared, Fastify will always choose the highest compatible with the `Accept-Version` header value.
If the request lacks an `Accept-Version` header, a 404 error will be returned.
Custom version matching logic can be defined through the [`constraints`](https://fastify.dev/docs/v5.4.x/Reference/Server/#constraints)
configuration when creating a Fastify server instance.
#### Host Constraints[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#host-constraints "Direct link to Host Constraints")
Provide a `host` key in the `constraints` route option to limit the route to certain values of the request `Host` header. `host` constraint values can be specified as strings for exact matches or RegExps for arbitrary host matching.
fastify.route({ method: 'GET', url: '/', constraints: { host: 'auth.fastify.dev' }, handler: function (request, reply) { reply.send('hello world from auth.fastify.dev') }})fastify.inject({ method: 'GET', url: '/', headers: { 'Host': 'example.com' }}, (err, res) => { // 404 because the host doesn't match the constraint})fastify.inject({ method: 'GET', url: '/', headers: { 'Host': 'auth.fastify.dev' }}, (err, res) => { // => 'hello world from auth.fastify.dev'})
RegExp `host` constraints can also be specified allowing constraining to hosts matching wildcard subdomains (or any other pattern):
fastify.route({ method: 'GET', url: '/', constraints: { host: /.*\.fastify\.dev/ }, // will match any subdomain of fastify.dev handler: function (request, reply) { reply.send('hello world from ' + request.headers.host) }})
#### Asynchronous Custom Constraints[](https://fastify.dev/docs/v5.4.x/Reference/Routes/#asynchronous-custom-constraints "Direct link to Asynchronous Custom Constraints")
Custom constraints can be provided, and the `constraint` criteria can be fetched from another source such as a database. Use asynchronous custom constraints as a last resort, as they impact router performance.
function databaseOperation(field, done) { done(null, field)}const secret = { // strategy name for referencing in the route handler `constraints` options name: 'secret', // storage factory for storing routes in the find-my-way route tree storage: function () { let handlers = {} return { get: (type) => { return handlers[type] || null }, set: (type, store) => { handlers[type] = store } } }, // function to get the value of the constraint from each incoming request deriveConstraint: (req, ctx, done) => { databaseOperation(req.headers['secret'], done) }, // optional flag marking if handlers without constraints can match requests that have a value for this constraint mustMatchWhenDerived: true}
> ⚠ Warning: When using asynchronous constraints, avoid returning errors inside the callback. If errors are unavoidable, provide a custom `frameworkErrors` handler to manage them. Otherwise, route selection may break or expose sensitive information.
>
> const Fastify = require('fastify')const fastify = Fastify({ frameworkErrors: function (err, res, res) { if (err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) { res.code(400) return res.send("Invalid header provided") } else { res.send(err) } }})
* [Routes](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes)
* [Full declaration](https://fastify.dev/docs/v5.4.x/Reference/Routes/#full-declaration)
* [Routes options](https://fastify.dev/docs/v5.4.x/Reference/Routes/#routes-options)
* [Shorthand declaration](https://fastify.dev/docs/v5.4.x/Reference/Routes/#shorthand-declaration)
* [Url building](https://fastify.dev/docs/v5.4.x/Reference/Routes/#url-building)
* [Async Await](https://fastify.dev/docs/v5.4.x/Reference/Routes/#async-await)
* [Promise resolution](https://fastify.dev/docs/v5.4.x/Reference/Routes/#promise-resolution)
* [Route Prefixing](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing)
* [Route Prefixing and fastify-plugin](https://fastify.dev/docs/v5.4.x/Reference/Routes/#route-prefixing-and-fastify-plugin)
* [Custom Log Level](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-level)
* [Custom Log Serializer](https://fastify.dev/docs/v5.4.x/Reference/Routes/#custom-log-serializer)
* [Config](https://fastify.dev/docs/v5.4.x/Reference/Routes/#config)
* [Constraints](https://fastify.dev/docs/v5.4.x/Reference/Routes/#constraints)
---
# Reply | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Reply/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Reply/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Reply[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply "Direct link to Reply")
----------------------------------------------------------------------------------------
* [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.3.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.3.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.3.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.3.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headerkey-value)
* [.headers(object)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#redirectdest--code)
* [.callNotFound()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getserializationfunctionschema--httpstatus)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#compileserializationschemaschema-httpstatus)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus)
* [.serializer(func)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.3.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.3.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#senddata)
* [Objects](https://fastify.dev/docs/v5.3.x/Reference/Reply/#objects)
* [Strings](https://fastify.dev/docs/v5.3.x/Reference/Reply/#strings)
* [Streams](https://fastify.dev/docs/v5.3.x/Reference/Reply/#streams)
* [Buffers](https://fastify.dev/docs/v5.3.x/Reference/Reply/#buffers)
* [TypedArrays](https://fastify.dev/docs/v5.3.x/Reference/Reply/#typedarrays)
* [ReadableStream](https://fastify.dev/docs/v5.3.x/Reference/Reply/#readablestream)
* [Response](https://fastify.dev/docs/v5.3.x/Reference/Reply/#response)
* [Errors](https://fastify.dev/docs/v5.3.x/Reference/Reply/#errors)
* [Type of the final payload](https://fastify.dev/docs/v5.3.x/Reference/Reply/#type-of-the-final-payload)
* [Async-Await and Promises](https://fastify.dev/docs/v5.3.x/Reference/Reply/#async-await-and-promises)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#thenfulfilled-rejected)
### Introduction[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#introduction "Direct link to Introduction")
The second parameter of the handler function is `Reply`. Reply is a core Fastify object that exposes the following functions and properties:
* `.code(statusCode)` - Sets the status code.
* `.status(statusCode)` - An alias for `.code(statusCode)`.
* `.statusCode` - Read and set the HTTP status code.
* `.elapsedTime` - Returns the amount of time passed since the request was received by Fastify.
* `.server` - A reference to the fastify instance object.
* `.header(name, value)` - Sets a response header.
* `.headers(object)` - Sets all the keys of the object as response headers.
* `.getHeader(name)` - Retrieve value of already set header.
* `.getHeaders()` - Gets a shallow copy of all current response headers.
* `.removeHeader(key)` - Remove the value of a previously set header.
* `.hasHeader(name)` - Determine if a header has been set.
* `.writeEarlyHints(hints, callback)` - Sends early hints to the user while the response is being prepared.
* `.trailer(key, function)` - Sets a response trailer.
* `.hasTrailer(key)` - Determine if a trailer has been set.
* `.removeTrailer(key)` - Remove the value of a previously set trailer.
* `.type(value)` - Sets the header `Content-Type`.
* `.redirect(dest, [code,])` - Redirect to the specified URL, the status code is optional (defaults to `302`).
* `.callNotFound()` - Invokes the custom not found handler.
* `.serialize(payload)` - Serializes the specified payload using the default JSON serializer or using the custom serializer (if one is set) and returns the serialized payload.
* `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the serialization function for the specified schema or http status, if any of either are set.
* `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles the specified schema and returns a serialization function using the default (or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded to the `SerializerCompiler` if provided, default to `undefined`.
* `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes the specified data using the specified schema and returns the serialized payload. If the optional `httpStatus`, and `contentType` are provided, the function will use the serializer function given for that specific content type and HTTP Status Code. Default to `undefined`.
* `.serializer(function)` - Sets a custom serializer for the payload.
* `.send(payload)` - Sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object.
* `.sent` - A boolean value that you can use if you need to know if `send` has already been called.
* `.hijack()` - interrupt the normal request lifecycle.
* `.raw` - The [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core.
* `.log` - The logger instance of the incoming request.
* `.request` - The incoming request.
fastify.get('/', options, function (request, reply) { // Your code reply .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ hello: 'world' })})
### .code(statusCode)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#codestatuscode "Direct link to .code(statusCode)")
If not set via `reply.code`, the resulting `statusCode` will be `200`.
### .elapsedTime[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#elapsedtime "Direct link to .elapsedTime")
Invokes the custom response time getter to calculate the amount of time passed since the request was received by Fastify.
const milliseconds = reply.elapsedTime
### .statusCode[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#statuscode "Direct link to .statusCode")
This property reads and sets the HTTP status code. It is an alias for `reply.code()` when used as a setter.
if (reply.statusCode >= 299) { reply.statusCode = 500}
### .server[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#server "Direct link to .server")
The Fastify server instance, scoped to the current [encapsulation context](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/)
.
fastify.decorate('util', function util () { return 'foo'})fastify.get('/', async function (req, rep) { return rep.server.util() // foo})
### .header(key, value)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headerkey-value "Direct link to .header(key, value)")
Sets a response header. If the value is omitted or undefined, it is coerced to `''`.
> 🛈 Note: The header's value must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid characters will result in a 500 `TypeError` response.
For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value)
.
* ### set-cookie[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#set-cookie "Direct link to set-cookie")
* When sending different values as a cookie with `set-cookie` as the key, every value will be sent as a cookie instead of replacing the previous value.
reply.header('set-cookie', 'foo');reply.header('set-cookie', 'bar');
* The browser will only consider the latest reference of a key for the `set-cookie` header. This is done to avoid parsing the `set-cookie` header when added to a reply and speeds up the serialization of the reply.
* To reset the `set-cookie` header, you need to make an explicit call to `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)` [here](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removeheaderkey)
.
### .headers(object)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headersobject "Direct link to .headers(object)")
Sets all the keys of the object as response headers. [`.header`](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headerkey-value)
will be called under the hood.
reply.headers({ 'x-foo': 'foo', 'x-bar': 'bar'})
### .getHeader(key)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaderkey "Direct link to .getHeader(key)")
Retrieves the value of a previously set header.
reply.header('x-foo', 'foo') // setHeader: key, valuereply.getHeader('x-foo') // 'foo'
### .getHeaders()[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaders "Direct link to .getHeaders()")
Gets a shallow copy of all current response headers, including those set via the raw `http.ServerResponse`. Note that headers set via Fastify take precedence over those set via `http.ServerResponse`.
reply.header('x-foo', 'foo')reply.header('x-bar', 'bar')reply.raw.setHeader('x-foo', 'foo2')reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
### .removeHeader(key)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removeheaderkey "Direct link to .removeHeader(key)")
Remove the value of a previously set header.
reply.header('x-foo', 'foo')reply.removeHeader('x-foo')reply.getHeader('x-foo') // undefined
### .hasHeader(key)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hasheaderkey "Direct link to .hasHeader(key)")
Returns a boolean indicating if the specified header has been set.
### .writeEarlyHints(hints, callback)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#writeearlyhintshints-callback "Direct link to .writeEarlyHints(hints, callback)")
Sends early hints to the client. Early hints allow the client to start processing resources before the final response is sent. This can improve performance by allowing the client to preload or preconnect to resources while the server is still generating the response.
The hints parameter is an object containing the early hint key-value pairs.
Example:
reply.writeEarlyHints({ Link: '; rel=preload; as=style'});
The optional callback parameter is a function that will be called once the hint is sent or if an error occurs.
### .trailer(key, function)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#trailerkey-function "Direct link to .trailer(key, function)")
Sets a response trailer. Trailer is usually used when you need a header that requires heavy resources to be sent after the `data`, for example, `Server-Timing` and `Etag`. It can ensure the client receives the response data as soon as possible.
> 🛈 Note: The header `Transfer-Encoding: chunked` will be added once you use the trailer. It is a hard requirement for using trailer in Node.js.
> 🛈 Note: Any error passed to `done` callback will be ignored. If you interested in the error, you can turn on `debug` level logging.\*
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})const { createHash } = require('node:crypto')// trailer function also receive two argument// @param {object} reply fastify reply// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent// @param {function} done callback to set trailer valuereply.trailer('content-md5', function(reply, payload, done) { const hash = createHash('md5') hash.update(payload) done(null, hash.disgest('hex'))})// when you prefer async-awaitreply.trailer('content-md5', async function(reply, payload) { const hash = createHash('md5') hash.update(payload) return hash.disgest('hex')})
### .hasTrailer(key)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hastrailerkey "Direct link to .hasTrailer(key)")
Returns a boolean indicating if the specified trailer has been set.
### .removeTrailer(key)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removetrailerkey "Direct link to .removeTrailer(key)")
Remove the value of a previously set trailer.
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})reply.removeTrailer('server-timing')reply.getTrailer('server-timing') // undefined
### .redirect(dest, \[code ,\])[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#redirectdest-code- "Direct link to .redirect(dest, [code ,])")
Redirects a request to the specified URL, the status code is optional, default to `302` (if status code is not already set by calling `code`).
> 🛈 Note: The input URL must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid URLs will result in a 500 `TypeError` response.
Example (no `reply.code()` call) sets status code to `302` and redirects to `/home`
reply.redirect('/home')
Example (no `reply.code()` call) sets status code to `303` and redirects to `/home`
reply.redirect('/home', 303)
Example (`reply.code()` call) sets status code to `303` and redirects to `/home`
reply.code(303).redirect('/home')
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
reply.code(303).redirect('/home', 302)
### .callNotFound()[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#callnotfound "Direct link to .callNotFound()")
Invokes the custom not found handler. Note that it will only call `preHandler` hook specified in [`setNotFoundHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#set-not-found-handler)
.
reply.callNotFound()
### .type(contentType)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#typecontenttype "Direct link to .type(contentType)")
Sets the content type for the response. This is a shortcut for `reply.header('Content-Type', 'the/type')`.
reply.type('text/html')
If the `Content-Type` has a JSON subtype, and the charset parameter is not set, `utf-8` will be used as the charset by default. For other content types, the charset must be set explicitly.
### .getSerializationFunction(schema | httpStatus, \[contentType\])[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype "Direct link to .getSerializationFunction(schema | httpStatus, [contentType])")
By calling this function using a provided `schema` or `httpStatus`, and the optional `contentType`, it will return a `serialzation` function that can be used to serialize diverse inputs. It returns `undefined` if no serialization function was found using either of the provided inputs.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .getSerializationFunction({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200, 'application/json')serialize({ foo: 'bar' }) // '{"foo":"bar"}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .compileSerializationSchema(schema, \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype "Direct link to .compileSerializationSchema(schema, [httpStatus], [contentType])")
This function will compile a serialization schema and return a function that can be used to serialize data. The function returned (a.k.a. _serialization function_) returned is compiled by using the provided `SerializerCompiler`. Also this is cached by using a `WeakMap` for reducing compilation calls.
The optional parameters `httpStatus` and `contentType`, if provided, are forwarded directly to the `SerializerCompiler`, so it can be used to compile the serialization function if a custom `SerializerCompiler` is used.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } }, 200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ '3xx': { content: { 'application/json': { schema: { name: { type: 'string' }, phone: { type: 'number' } } } } } }, '3xx', 'application/json')serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
Note that you should be careful when using this function, as it will cache the compiled serialization functions based on the schema provided. If the schemas provided is mutated or changed, the serialization functions will not detect that the schema has been altered and for instance it will reuse the previously compiled serialization function based on the reference of the schema previously provided.
If there's a need to change the properties of a schema, always opt to create a totally new object, otherwise the implementation won't benefit from the cache mechanism.
:Using the following schema as example:
const schema1 = { type: 'object', properties: { foo: { type: 'string' } }}
_Not_
const serialize = reply.compileSerializationSchema(schema1)// Later on...schema1.properties.foo.type. = 'integer'const newSerialize = reply.compileSerializationSchema(schema1)console.log(newSerialize === serialize) // true
_Instead_
const serialize = reply.compileSerializationSchema(schema1)// Later on...const newSchema = Object.assign({}, schema1)newSchema.properties.foo.type = 'integer'const newSerialize = reply.compileSerializationSchema(newSchema)console.log(newSerialize === serialize) // false
### .serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype "Direct link to .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])")
This function will serialize the input data based on the provided schema or HTTP status code. If both are provided the `httpStatus` will take precedence.
If there is not a serialization function for a given `schema` a new serialization function will be compiled, forwarding the `httpStatus` and `contentType` if provided.
reply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }, 200) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'// orreply .serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .serializer(func)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializerfunc "Direct link to .serializer(func)")
By default, `.send()` will JSON-serialize any value that is not one of `Buffer`, `stream`, `string`, `undefined`, or `Error`. If you need to replace the default serializer with a custom serializer for a particular request, you can do so with the `.serializer()` utility. Be aware that if you are using a custom serializer, you must set a custom `'Content-Type'` header.
reply .header('Content-Type', 'application/x-protobuf') .serializer(protoBuf.serialize)
Note that you don't need to use this utility inside a `handler` because Buffers, streams, and strings (unless a serializer is set) are considered to already be serialized.
reply .header('Content-Type', 'application/x-protobuf') .send(protoBuf.serialize(data))
See [`.send()`](https://fastify.dev/docs/v5.3.x/Reference/Reply/#send)
for more information on sending different types of values.
### .raw[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#raw "Direct link to .raw")
This is the [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core. Whilst you are using the Fastify `Reply` object, the use of `Reply.raw` functions is at your own risk as you are skipping all the Fastify logic of handling the HTTP response. e.g.:
app.get('/cookie-2', (req, reply) => { reply.setCookie('session', 'value', { secure: false }) // this will not be used // in this case we are using only the nodejs http server response object reply.raw.writeHead(200, { 'Content-Type': 'text/plain' }) reply.raw.write('ok') reply.raw.end()})
Another example of the misuse of `Reply.raw` is explained in [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaders)
.
### .sent[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#sent "Direct link to .sent")
As the name suggests, `.sent` is a property to indicate if a response has been sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was used.
In case a route handler is defined as an async function or it returns a promise, it is possible to call `reply.hijack()` to indicate that the automatic invocation of `reply.send()` once the handler promise resolve should be skipped. By calling `reply.hijack()`, an application claims full responsibility for the low-level request and response. Moreover, hooks will not be invoked.
_Modifying the `.sent` property directly is deprecated. Please use the aforementioned `.hijack()` method to achieve the same effect._
### .hijack()[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hijack "Direct link to .hijack()")
Sometimes you might need to halt the execution of the normal request lifecycle and handle sending the response manually.
To achieve this, Fastify provides the `reply.hijack()` method that can be called during the request lifecycle (At any point before `reply.send()` is called), and allows you to prevent Fastify from sending the response, and from running the remaining hooks (and user handler if the reply was hijacked before).
app.get('/', (req, reply) => { reply.hijack() reply.raw.end('hello world') return Promise.resolve('this will be skipped')})
If `reply.raw` is used to send a response back to the user, the `onResponse` hooks will still be executed.
### .send(data)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#senddata "Direct link to .send(data)")
As the name suggests, `.send()` is the function that sends the payload to the end user.
#### Objects[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#objects "Direct link to Objects")
As noted above, if you are sending JSON objects, `send` will serialize the object with [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
if you set an output schema, otherwise, `JSON.stringify()` will be used.
fastify.get('/json', options, function (request, reply) { reply.send({ hello: 'world' })})
#### Strings[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#strings "Direct link to Strings")
If you pass a string to `send` without a `Content-Type`, it will be sent as `text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a string to `send`, it will be serialized with the custom serializer if one is set, otherwise, it will be sent unmodified (unless the `Content-Type` header is set to `application/json; charset=utf-8`, in which case it will be JSON-serialized like an object — see the section above).
fastify.get('/json', options, function (request, reply) { reply.send('plain string')})
#### Streams[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#streams "Direct link to Streams")
If you are sending a stream and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, streams are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') reply.send(stream)})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') return reply.send(stream)})
#### Buffers[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#buffers "Direct link to Buffers")
If you are sending a buffer and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) })})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) }) return reply})
#### TypedArrays[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#typedarrays "Direct link to TypedArrays")
`send` manages TypedArray like a Buffer, and sets the `'Content-Type'` header to `'application/octet-stream'` if not already set.
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const typedArray = new Uint16Array(10) reply.send(typedArray)})
#### ReadableStream[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#readablestream "Direct link to ReadableStream")
`ReadableStream` will be treated as a node stream mentioned above, the content is considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') reply.header('Content-Type', 'application/octet-stream') reply.send(ReadableStream.from(stream))})
#### Response[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#response "Direct link to Response")
`Response` allows to manage the reply payload, status code and headers in one place. The payload provided inside `Response` is considered to be pre-serialized, so they will be sent unmodified without response validation.
Please be aware when using `Response`, the status code and headers will not directly reflect to `reply.statusCode` and `reply.getHeaders()`. Such behavior is based on `Response` only allow `readonly` status code and headers. The data is not allow to be bi-direction editing, and may confuse when checking the `payload` in `onSend` hooks.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') const readableStream = ReadableStream.from(stream) const response = new Response(readableStream, { status: 200, headers: { 'content-type': 'application/octet-stream' } }) reply.send(response)})
#### Errors[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#errors "Direct link to Errors")
If you pass to _send_ an object that is an instance of _Error_, Fastify will automatically create an error structured as the following:
{ error: String // the HTTP error message code: String // the Fastify error code message: String // the user error message statusCode: Number // the HTTP status code}
You can add custom properties to the Error object, such as `headers`, that will be used to enhance the HTTP response.
> 🛈 Note: If you are passing an error to `send` and the statusCode is less than 400, Fastify will automatically set it at 500.
Tip: you can simplify errors by using the [`http-errors`](https://npm.im/http-errors)
module or [`@fastify/sensible`](https://github.com/fastify/fastify-sensible)
plugin to generate errors:
fastify.get('/', function (request, reply) { reply.send(httpErrors.Gone())})
To customize the JSON error output you can do it by:
* setting a response JSON schema for the status code you need
* add the additional properties to the `Error` instance
Notice that if the returned status code is not in the response schema list, the default behavior will be applied.
fastify.get('/', { schema: { response: { 501: { type: 'object', properties: { statusCode: { type: 'number' }, code: { type: 'string' }, error: { type: 'string' }, message: { type: 'string' }, time: { type: 'string' } } } } }}, function (request, reply) { const error = new Error('This endpoint has not been implemented') error.time = 'it will be implemented in two weeks' reply.code(501).send(error)})
If you want to customize error handling, check out [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
API.
> 🛈 Note: you are responsible for logging when customizing the error handler.
API:
fastify.setErrorHandler(function (error, request, reply) { request.log.warn(error) const statusCode = error.statusCode >= 400 ? error.statusCode : 500 reply .code(statusCode) .type('text/plain') .send(statusCode >= 500 ? 'Internal server error' : error.message)})
Beware that calling `reply.send(error)` in your custom error handler will send the error to the default error handler. Check out the [Reply Lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#reply-lifecycle)
for more information.
The not found errors generated by the router will use the [`setNotFoundHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#setnotfoundhandler)
API:
fastify.setNotFoundHandler(function (request, reply) { reply .code(404) .type('text/plain') .send('a custom not found')})
#### Type of the final payload[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#type-of-the-final-payload "Direct link to Type of the final payload")
The type of the sent payload (after serialization and going through any [`onSend` hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onsend)
) must be one of the following types, otherwise, an error will be thrown:
* `string`
* `Buffer`
* `stream`
* `undefined`
* `null`
#### Async-Await and Promises[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#async-await-and-promises "Direct link to Async-Await and Promises")
Fastify natively handles promises and supports async-await.
_Note that in the following examples we are not using reply.send._
const { promisify } = require('node:util')const delay = promisify(setTimeout)fastify.get('/promises', options, function (request, reply) { return delay(200).then(() => { return { hello: 'world' }})})fastify.get('/async-await', options, async function (request, reply) { await delay(200) return { hello: 'world' }})
Rejected promises default to a `500` HTTP status code. Reject the promise, or `throw` in an `async function`, with an object that has `statusCode` (or `status`) and `message` properties to modify the reply.
fastify.get('/teapot', async function (request, reply) { const err = new Error() err.statusCode = 418 err.message = 'short and stout' throw err})fastify.get('/botnet', async function (request, reply) { throw { statusCode: 418, message: 'short and stout' } // will return to the client the same json})
If you want to know more please review [Routes#async-await](https://fastify.dev/docs/v5.3.x/Reference/Routes/#async-await)
.
### .then(fulfilled, rejected)[](https://fastify.dev/docs/v5.3.x/Reference/Reply/#thenfulfilled-rejected "Direct link to .then(fulfilled, rejected)")
As the name suggests, a `Reply` object can be awaited upon, i.e. `await reply` will wait until the reply is sent. The `await` syntax calls the `reply.then()`.
`reply.then(fulfilled, rejected)` accepts two parameters:
* `fulfilled` will be called when a response has been fully sent,
* `rejected` will be called if the underlying stream had an error, e.g. the socket has been destroyed.
For more details, see:
* [https://github.com/fastify/fastify/issues/1864](https://github.com/fastify/fastify/issues/1864)
for the discussion about this feature
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Promise/then](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
for the signature
* [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.3.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.3.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.3.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.3.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headerkey-value)
* [set-cookie](https://fastify.dev/docs/v5.3.x/Reference/Reply/#set-cookie)
* [.headers(object)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#redirectdest-code-)
* [.callNotFound()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype)
* [.serializer(func)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.3.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.3.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.3.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#senddata)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#thenfulfilled-rejected)
---
# TypeScript | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
TypeScript[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#typescript "Direct link to TypeScript")
------------------------------------------------------------------------------------------------------------
The Fastify framework is written in vanilla JavaScript, and as such type definitions are not as easy to maintain; however, since version 2 and beyond, maintainers and contributors have put in a great effort to improve the types.
The type system was changed in Fastify version 3. The new type system introduces generic constraining and defaulting, plus a new way to define schema types such as a request body, querystring, and more! As the team works on improving framework and type definition synergy, sometimes parts of the API will not be typed or may be typed incorrectly. We encourage you to **contribute** to help us fill in the gaps. Just make sure to read our [`CONTRIBUTING.md`](https://github.com/fastify/fastify/blob/main/CONTRIBUTING.md)
file before getting started to make sure things go smoothly!
> The documentation in this section covers Fastify version 3.x typings
> Plugins may or may not include typings. See [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
> for more information. We encourage users to send pull requests to improve typings support.
🚨 Don't forget to install `@types/node`
Learn By Example[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#learn-by-example "Direct link to Learn By Example")
------------------------------------------------------------------------------------------------------------------------------
The best way to learn the Fastify type system is by example! The following four examples should cover the most common Fastify development cases. After the examples there is further, more detailed documentation for the type system.
### Getting Started[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#getting-started "Direct link to Getting Started")
This example will get you up and running with Fastify and TypeScript. It results in a blank http Fastify server.
1. Create a new npm project, install Fastify, and install typescript & Node.js types as peer dependencies:
npm init -ynpm i fastifynpm i -D typescript @types/node
2. Add the following lines to the `"scripts"` section of the `package.json`:
{ "scripts": { "build": "tsc -p tsconfig.json", "start": "node index.js" }}
3. Initialize a TypeScript configuration file:
npx tsc --init
or use one of the [recommended ones](https://github.com/tsconfig/bases#node-14-tsconfigjson)
.
_Note: Set `target` property in `tsconfig.json` to `es2017` or greater to avoid [FastifyDeprecation](https://github.com/fastify/fastify/issues/3284)
warning._
4. Create an `index.ts` file - this will contain the server code
5. Add the following code block to your file:
import fastify from 'fastify'const server = fastify()server.get('/ping', async (request, reply) => { return 'pong\n'})server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(1) } console.log(`Server listening at ${address}`)})
6. Run `npm run build` - this will compile `index.ts` into `index.js` which can be executed using Node.js. If you run into any errors please open an issue in [fastify/help](https://github.com/fastify/help/)
7. Run `npm run start` to run the Fastify server
8. You should see `Server listening at http://127.0.0.1:8080` in your console
9. Try out your server using `curl localhost:8080/ping`, it should return `pong` 🏓
🎉 You now have a working Typescript Fastify server! This example demonstrates the simplicity of the version 3.x type system. By default, the type system assumes you are using an `http` server. The later examples will demonstrate how to create more complex servers such as `https` and `http2`, how to specify route schemas, and more!
> For more examples on initializing Fastify with TypeScript (such as enabling HTTP2) check out the detailed API section [here](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
### Using Generics[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#using-generics "Direct link to Using Generics")
The type system heavily relies on generic properties to provide the most accurate development experience. While some may find the overhead a bit cumbersome, the tradeoff is worth it! This example will dive into implementing generic types for route schemas and the dynamic properties located on the route-level `request` object.
1. If you did not complete the previous example, follow steps 1-4 to get set up.
2. Inside `index.ts`, define three interfaces `IQuerystring`,`IHeaders` and `IReply`:
interface IQuerystring { username: string; password: string;}interface IHeaders { 'h-Custom': string;}interface IReply { 200: { success: boolean }; 302: { url: string }; '4xx': { error: string };}
3. Using the three interfaces, define a new API route and pass them as generics. The shorthand route methods (i.e. `.get`) accept a generic object `RouteGenericInterface` containing five named properties: `Body`, `Querystring`, `Params`, `Headers` and `Reply`. The interfaces `Body`, `Querystring`, `Params` and `Headers` will be passed down through the route method into the route method handler `request` instance and the `Reply` interface to the `reply` instance.
server.get<{ Querystring: IQuerystring, Headers: IHeaders, Reply: IReply}>('/auth', async (request, reply) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] // do something with request data // chaining .statusCode/.code calls with .send allows type narrowing. For example: // this works reply.code(200).send({ success: true }); // but this gives a type error reply.code(200).send('uh-oh'); // it even works for wildcards reply.code(404).send({ error: 'Not found' }); return `logged in!`})
4. Build and run the server code with `npm run build` and `npm run start`
5. Query the API
curl localhost:8080/auth?username=admin&password=Password123!
And it should return back `logged in!`
6. But wait there's more! The generic interfaces are also available inside route level hook methods. Modify the previous route by adding a `preValidation` hook:
server.get<{ Querystring: IQuerystring, Headers: IHeaders, Reply: IReply}>('/auth', { preValidation: (request, reply, done) => { const { username, password } = request.query done(username !== 'admin' ? new Error('Must be admin') : undefined) // only validate `admin` account }}, async (request, reply) => { const customerHeader = request.headers['h-Custom'] // do something with request data return `logged in!`})
7. Build and run and query with the `username` query string option set to anything other than `admin`. The API should now return a HTTP 500 error `{"statusCode":500,"error":"Internal Server Error","message":"Must be admin"}`
🎉 Good work, now you can define interfaces for each route and have strictly typed request and reply instances. Other parts of the Fastify type system rely on generic properties. Make sure to reference the detailed type system documentation below to learn more about what is available.
### JSON Schema[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#json-schema "Direct link to JSON Schema")
To validate your requests and responses you can use JSON Schema files. If you didn't know already, defining schemas for your Fastify routes can increase their throughput! Check out the [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/)
documentation for more info.
Also it has the advantage to use the defined type within your handlers (including pre-validation, etc.).
Here are some options on how to achieve this.
#### Fastify Type Providers[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastify-type-providers "Direct link to Fastify Type Providers")
Fastify offers two packages wrapping `json-schema-to-ts` and `typebox`:
* [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
* [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
And a `zod` wrapper by a third party called [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
They simplify schema validation setup and you can read more about them in [Type Providers](https://fastify.dev/docs/v5.4.x/Reference/Type-Providers/)
page.
Below is how to setup schema validation using the `typebox`, `json-schema-to-typescript`, and `json-schema-to-ts` packages without type providers.
#### TypeBox[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#typebox "Direct link to TypeBox")
A useful library for building types and a schema at once is [TypeBox](https://www.npmjs.com/package/@sinclair/typebox)
. With TypeBox you define your schema within your code and use them directly as types or schemas as you need them.
When you want to use it for validation of some payload in a fastify route you can do it as follows:
1. Install `typebox` in your project.
npm i @sinclair/typebox
2. Define the schema you need with `Type` and create the respective type with `Static`.
import { Static, Type } from '@sinclair/typebox'export const User = Type.Object({ name: Type.String(), mail: Type.Optional(Type.String({ format: 'email' })),})export type UserType = Static
3. Use the defined type and schema during the definition of your route
import Fastify from 'fastify'// ...const fastify = Fastify()fastify.post<{ Body: UserType, Reply: UserType }>( '/', { schema: { body: User, response: { 200: User }, }, }, (request, reply) => { // The `name` and `mail` types are automatically inferred const { name, mail } = request.body; reply.status(200).send({ name, mail }); })
#### json-schema-to-typescript[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#json-schema-to-typescript "Direct link to json-schema-to-typescript")
In the last example we used Typebox to define the types and schemas for our route. Many users will already be using JSON Schemas to define these properties, and luckily there is a way to transform existing JSON Schemas into TypeScript interfaces!
1. If you did not complete the 'Getting Started' example, go back and follow steps 1-4 first.
2. Install the `json-schema-to-typescript` module:
npm i -D json-schema-to-typescript
3. Create a new folder called `schemas` and add two files `headers.json` and `querystring.json`. Copy and paste the following schema definitions into the respective files:
{ "title": "Headers Schema", "type": "object", "properties": { "h-Custom": { "type": "string" } }, "additionalProperties": false, "required": ["h-Custom"]}
{ "title": "Querystring Schema", "type": "object", "properties": { "username": { "type": "string" }, "password": { "type": "string" } }, "additionalProperties": false, "required": ["username", "password"]}
4. Add a `compile-schemas` script to the package.json:
{ "scripts": { "compile-schemas": "json2ts -i schemas -o types" } }
`json2ts` is a CLI utility included in `json-schema-to-typescript`. `schemas` is the input path, and `types` is the output path. 5. Run `npm run compile-schemas`. Two new files should have been created in the `types` directory. 6. Update `index.ts` to have the following code:
import fastify from 'fastify' // import json schemas as normal import QuerystringSchema from './schemas/querystring.json' import HeadersSchema from './schemas/headers.json' // import the generated interfaces import { QuerystringSchema as QuerystringSchemaInterface } from './types/querystring' import { HeadersSchema as HeadersSchemaInterface } from './types/headers' const server = fastify() server.get<{ Querystring: QuerystringSchemaInterface, Headers: HeadersSchemaInterface }>('/auth', { schema: { querystring: QuerystringSchema, headers: HeadersSchema }, preValidation: (request, reply, done) => { const { username, password } = request.query done(username !== 'admin' ? new Error('Must be admin') : undefined) } // or if using async // preValidation: async (request, reply) => { // const { username, password } = request.query // if (username !== "admin") throw new Error("Must be admin"); // } }, async (request, reply) => { const customerHeader = request.headers['h-Custom'] // do something with request data return `logged in!` }) server.route<{ Querystring: QuerystringSchemaInterface, Headers: HeadersSchemaInterface }>({ method: 'GET', url: '/auth2', schema: { querystring: QuerystringSchema, headers: HeadersSchema }, preHandler: (request, reply, done) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] done() }, handler: (request, reply) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] reply.status(200).send({username}); } }) server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(0) } console.log(`Server listening at ${address}`) })
Pay special attention to the imports at the top of this file. It might seem redundant, but you need to import both the schema files and the generated interfaces.
Great work! Now you can make use of both JSON Schemas and TypeScript definitions.
#### json-schema-to-ts[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#json-schema-to-ts "Direct link to json-schema-to-ts")
If you do not want to generate types from your schemas, but want to use them directly from your code, you can use the package [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts)
.
You can install it as dev-dependency.
npm i -D json-schema-to-ts
In your code you can define your schema like a normal object. But be aware of making it _const_ like explained in the docs of the module.
const todo = { type: 'object', properties: { name: { type: 'string' }, description: { type: 'string' }, done: { type: 'boolean' }, }, required: ['name'],} as const; // don't forget to use const !
With the provided type `FromSchema` you can build a type from your schema and use it in your handler.
import { FromSchema } from "json-schema-to-ts";fastify.post<{ Body: FromSchema }>( '/todo', { schema: { body: todo, response: { 201: { type: 'string', }, }, } }, async (request, reply): Promise => { /* request.body has type { [x: string]: unknown; description?: string; done?: boolean; name: string; } */ request.body.name // will not throw type error request.body.notthere // will throw type error reply.status(201).send(); },);
### Plugins[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins "Direct link to Plugins")
One of Fastify's most distinguishable features is its extensive plugin ecosystem. Plugin types are fully supported, and take advantage of the [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)
pattern. This example is broken up into three parts: Creating a TypeScript Fastify Plugin, Creating Type Definitions for a Fastify Plugin, and Using a Fastify Plugin in a TypeScript Project.
#### Creating a TypeScript Fastify Plugin[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#creating-a-typescript-fastify-plugin "Direct link to Creating a TypeScript Fastify Plugin")
1. Initialize a new npm project and install required dependencies
npm init -ynpm i fastify fastify-pluginnpm i -D typescript @types/node
2. Add a `build` script to the `"scripts"` section and `'index.d.ts'` to the `"types"` section of the `package.json` file:
{ "types": "index.d.ts", "scripts": { "build": "tsc -p tsconfig.json" }}
3. Initialize a TypeScript configuration file:
npx typescript --init
Once the file is generated, enable the `"declaration"` option in the `"compilerOptions"` object.
{ "compilerOptions": { "declaration": true }}
4. Create an `index.ts` file - this will contain the plugin code
5. Add the following code to `index.ts`
import { FastifyPluginCallback, FastifyPluginAsync } from 'fastify'import fp from 'fastify-plugin'// using declaration merging, add your plugin props to the appropriate fastify interfaces// if prop type is defined here, the value will be typechecked when you call decorate{,Request,Reply}declare module 'fastify' { interface FastifyRequest { myPluginProp: string } interface FastifyReply { myPluginProp: number }}// define optionsexport interface MyPluginOptions { myPluginOption: string}// define plugin using callbacksconst myPluginCallback: FastifyPluginCallback = (fastify, options, done) => { fastify.decorateRequest('myPluginProp', 'super_secret_value') fastify.decorateReply('myPluginProp', options.myPluginOption) done()}// define plugin using promisesconst myPluginAsync: FastifyPluginAsync = async (fastify, options) => { fastify.decorateRequest('myPluginProp', 'super_secret_value') fastify.decorateReply('myPluginProp', options.myPluginOption)}// export plugin using fastify-pluginexport default fp(myPluginCallback, '3.x')// or// export default fp(myPluginAsync, '3.x')
6. Run `npm run build` to compile the plugin code and produce both a JavaScript source file and a type definition file.
7. With the plugin now complete you can \[publish to npm\] or use it locally.
> You do not _need_ to publish your plugin to npm to use it. You can include it in a Fastify project and reference it as you would any piece of code! As a TypeScript user, make sure the declaration override exists somewhere that will be included in your project compilation so the TypeScript interpreter can process it.
#### Creating Type Definitions for a Fastify Plugin[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#creating-type-definitions-for-a-fastify-plugin "Direct link to Creating Type Definitions for a Fastify Plugin")
This plugin guide is for Fastify plugins written in JavaScript. The steps outlined in this example are for adding TypeScript support for users consuming your plugin.
1. Initialize a new npm project and install required dependencies
npm init -ynpm i fastify-plugin
2. Create two files `index.js` and `index.d.ts`
3. Modify the package json to include these files under the `main` and `types` properties (the name does not have to be `index` explicitly, but it is recommended the files have the same name):
{ "main": "index.js", "types": "index.d.ts"}
4. Open `index.js` and add the following code:
// fastify-plugin is highly recommended for any plugin you writeconst fp = require('fastify-plugin')function myPlugin (instance, options, done) { // decorate the fastify instance with a custom function called myPluginFunc instance.decorate('myPluginFunc', (input) => { return input.toUpperCase() }) done()}module.exports = fp(myPlugin, { fastify: '5.x', name: 'my-plugin' // this is used by fastify-plugin to derive the property name})
5. Open `index.d.ts` and add the following code:
import { FastifyPluginCallback } from 'fastify'interface PluginOptions { //...}// Optionally, you can add any additional exports.// Here we are exporting the decorator we added.export interface myPluginFunc { (input: string): string}// Most importantly, use declaration merging to add the custom property to the Fastify type systemdeclare module 'fastify' { interface FastifyInstance { myPluginFunc: myPluginFunc }}// fastify-plugin automatically adds named export, so be sure to add also this type// the variable name is derived from `options.name` property if `module.exports.myPlugin` is missingexport const myPlugin: FastifyPluginCallback// fastify-plugin automatically adds `.default` property to the exported plugin. See the note belowexport default myPlugin
**Note**: [fastify-plugin](https://github.com/fastify/fastify-plugin)
v2.3.0 and newer, automatically adds `.default` property and a named export to the exported plugin. Be sure to `export default` and `export const myPlugin` in your typings to provide the best developer experience. For a complete example you can check out [@fastify/swagger](https://github.com/fastify/fastify-swagger/blob/main/index.d.ts)
.
With those files completed, the plugin is now ready to be consumed by any TypeScript project!
The Fastify plugin system enables developers to decorate the Fastify instance, and the request/reply instances. For more information check out this blog post on [Declaration Merging and Generic Inheritance](https://dev.to/ethanarrowood/is-declaration-merging-and-generic-inheritance-at-the-same-time-impossible-53cp)
.
#### Using a Plugin[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#using-a-plugin "Direct link to Using a Plugin")
Using a Fastify plugin in TypeScript is just as easy as using one in JavaScript. Import the plugin with `import/from` and you're all set -- except there is one exception users should be aware of.
Fastify plugins use declaration merging to modify existing Fastify type interfaces (check out the previous two examples for more details). Declaration merging is not very _smart_, meaning if the plugin type definition for a plugin is within the scope of the TypeScript interpreter, then the plugin types will be included **regardless** of if the plugin is being used or not. This is an unfortunate limitation of using TypeScript and is unavoidable as of right now.
However, there are a couple of suggestions to help improve this experience:
* Make sure the `no-unused-vars` rule is enabled in [ESLint](https://eslint.org/docs/rules/no-unused-vars)
and any imported plugin are actually being loaded.
* Use a module such as [depcheck](https://www.npmjs.com/package/depcheck)
or [npm-check](https://www.npmjs.com/package/npm-check)
to verify plugin dependencies are being used somewhere in your project.
Note that using `require` will not load the type definitions properly and may cause type errors. TypeScript can only identify the types that are directly imported into code, which means that you can use require inline with import on top. For example:
import 'plugin' // here will trigger the type augmentation.fastify.register(require('plugin'))
import plugin from 'plugin' // here will trigger the type augmentation.fastify.register(plugin)
Or even explicit config on tsconfig
{ "types": ["plugin"] // we force TypeScript to import the types}
Code Completion In Vanilla JavaScript[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#code-completion-in-vanilla-javascript "Direct link to Code Completion In Vanilla JavaScript")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Vanilla JavaScript can use the published types to provide code completion (e.g. [Intellisense](https://code.visualstudio.com/docs/editor/intellisense)
) by following the [TypeScript JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
.
For example:
/** @type {import('fastify').FastifyPluginAsync<{ optionA: boolean, optionB: string }>} */module.exports = async function (fastify, { optionA, optionB }) { fastify.get('/look', () => 'at me');}
API Type System Documentation[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#api-type-system-documentation "Direct link to API Type System Documentation")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
This section is a detailed account of all the types available to you in Fastify version 3.x
All `http`, `https`, and `http2` types are inferred from `@types/node`
[Generics](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#generics)
are documented by their default value as well as their constraint value(s). Read these articles for more information on TypeScript generics.
* [Generic Parameter Default](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#generic-parameter-defaults)
* [Generic Constraints](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints)
#### How to import[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#how-to-import "Direct link to How to import")
The Fastify API is powered by the `fastify()` method. In JavaScript you would import it using `const fastify = require('fastify')`. In TypeScript it is recommended to use the `import/from` syntax instead so types can be resolved. There are a couple supported import methods with the Fastify type system.
1. `import fastify from 'fastify'`
* Types are resolved but not accessible using dot notation
* Example:
import fastify from 'fastify'const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Gain access to types with destructuring:
import fastify, { FastifyInstance } from 'fastify'const f: FastifyInstance = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Destructuring also works for the main API method:
import { fastify, FastifyInstance } from 'fastify'const f: FastifyInstance = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
2. `import * as Fastify from 'fastify'`
* Types are resolved and accessible using dot notation
* Calling the main Fastify API method requires a slightly different syntax (see example)
* Example:
import * as Fastify from 'fastify'const f: Fastify.FastifyInstance = Fastify.fastify()f.listen({ port: 8080 }, () => { console.log('running') })
3. `const fastify = require('fastify')`
* This syntax is valid and will import fastify as expected; however, types will **not** be resolved
* Example:
const fastify = require('fastify')const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Destructuring is supported and will resolve types properly
const { fastify } = require('fastify')const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
#### Generics[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#generics "Direct link to Generics")
Many type definitions share the same generic parameters; they are all documented, in detail, within this section.
Most definitions depend on `@types/node` modules `http`, `https`, and `http2`
##### RawServer[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver "Direct link to RawServer")
Underlying Node.js server type
Default: `http.Server`
Constraints: `http.Server`, `https.Server`, `http2.Http2Server`, `http2.Http2SecureServer`
Enforces generic parameters: [`RawRequest`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [`RawReply`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
##### RawRequest[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest "Direct link to RawRequest")
Underlying Node.js request type
Default: [`RawRequestDefaultExpression`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawrequestdefaultexpressionrawserver)
Constraints: `http.IncomingMessage`, `http2.Http2ServerRequest`
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
##### RawReply[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply "Direct link to RawReply")
Underlying Node.js response type
Default: [`RawReplyDefaultExpression`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawreplydefaultexpression)
Constraints: `http.ServerResponse`, `http2.Http2ServerResponse`
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
##### Logger[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger "Direct link to Logger")
Fastify logging utility
Default: [`FastifyLoggerOptions`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyloggeroptions)
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
##### RawBody[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawbody "Direct link to RawBody")
A generic parameter for the content-type-parser methods.
Constraints: `string | Buffer`
* * *
#### Fastify[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastify "Direct link to Fastify")
##### fastify< [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger)
\>(opts?: [FastifyServerOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyserveroptions-rawserver-logger)
): [FastifyInstance](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyinstance)
[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastify-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance "Direct link to fastify-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L19)
The main Fastify API method. By default creates an HTTP server. Utilizing discriminant unions and overload methods, the type system will automatically infer which type of server (http, https, or http2) is being created purely based on the options based to the method (see the examples below for more information). It also supports an extensive generic type system to allow the user to extend the underlying Node.js Server, Request, and Reply objects. Additionally, the `Logger` generic exists for custom log types. See the examples and generic breakdown below for more information.
###### Example 1: Standard HTTP server[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-1-standard-http-server "Direct link to Example 1: Standard HTTP server")
No need to specify the `Server` generic as the type system defaults to HTTP.
import fastify from 'fastify'const server = fastify()
Check out the Learn By Example - [Getting Started](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#getting-started)
example for a more detailed http server walkthrough.
###### Example 2: HTTPS server[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-2-https-server "Direct link to Example 2: HTTPS server")
1. Create the following imports from `@types/node` and `fastify`
import fs from 'node:fs'import path from 'node:path'import fastify from 'fastify'
2. Perform the following steps before setting up a Fastify HTTPS server to create the `key.pem` and `cert.pem` files:
openssl genrsa -out key.pemopenssl req -new -key key.pem -out csr.pemopenssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pemrm csr.pem
3. Instantiate a Fastify https server and add a route:
const server = fastify({ https: { key: fs.readFileSync(path.join(__dirname, 'key.pem')), cert: fs.readFileSync(path.join(__dirname, 'cert.pem')) }})server.get('/', async function (request, reply) { return { hello: 'world' }})server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(0) } console.log(`Server listening at ${address}`)})
4. Build and run! Test your server out by querying with: `curl -k https://localhost:8080`
###### Example 3: HTTP2 server[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-3-http2-server "Direct link to Example 3: HTTP2 server")
There are two types of HTTP2 server types, insecure and secure. Both require specifying the `http2` property as `true` in the `options` object. The `https` property is used for creating a secure http2 server; omitting the `https` property will create an insecure http2 server.
const insecureServer = fastify({ http2: true })const secureServer = fastify({ http2: true, https: {} // use the `key.pem` and `cert.pem` files from the https section})
For more details on using HTTP2 check out the Fastify [HTTP2](https://fastify.dev/docs/v5.4.x/Reference/HTTP2/)
documentation page.
###### Example 4: Extended HTTP server[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-4-extended-http-server "Direct link to Example 4: Extended HTTP server")
Not only can you specify the server type, but also the request and reply types. Thus, allowing you to specify special properties, methods, and more! When specified at server instantiation, the custom type becomes available on all further instances of the custom type.
import fastify from 'fastify'import http from 'node:http'interface customRequest extends http.IncomingMessage { mySpecialProp: string}const server = fastify()server.get('/', async (request, reply) => { const someValue = request.raw.mySpecialProp // TS knows this is a string, because of the `customRequest` interface return someValue.toUpperCase()})
###### Example 5: Specifying logger types[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-5-specifying-logger-types "Direct link to Example 5: Specifying logger types")
Fastify uses [Pino](https://getpino.io/#/)
logging library under the hood. Since `pino@7`, all of it's properties can be configured via `logger` field when constructing Fastify's instance. If properties you need aren't exposed, please open an Issue to [`Pino`](https://github.com/pinojs/pino/issues)
or pass a preconfigured external instance of Pino (or any other compatible logger) as temporary fix to Fastify via the same field. This allows creating custom serializers as well, see the [Logging](https://fastify.dev/docs/v5.4.x/Reference/Logging/)
documentation for more info.
import fastify from 'fastify'const server = fastify({ logger: { level: 'info', redact: ['x-userinfo'], messageKey: 'message' }})server.get('/', async (request, reply) => { server.log.info('log message') return 'another message'})
* * *
##### fastify.HTTPMethods[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyhttpmethods "Direct link to fastify.HTTPMethods")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L8)
Union type of: `'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'OPTIONS'`
##### fastify.RawServerBase[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserverbase "Direct link to fastify.RawServerBase")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L13)
Dependent on `@types/node` modules `http`, `https`, `http2`
Union type of: `http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer`
##### fastify.RawServerDefault[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserverdefault "Direct link to fastify.RawServerDefault")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L18)
Dependent on `@types/node` modules `http`
Type alias for `http.Server`
* * *
##### fastify.FastifyServerOptions< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [Logger](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyserveroptions-rawserver-logger "Direct link to fastifyfastifyserveroptions-rawserver-logger")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L29)
An interface of properties used in the instantiation of the Fastify server. Is used in the main [`fastify()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method. The `RawServer` and `Logger` generic parameters are passed down through that method.
See the main [fastify](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method type definition section for examples on instantiating a Fastify server with TypeScript.
##### fastify.FastifyInstance< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [Logger](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyinstance-rawserver-rawrequest-requestgeneric-logger "Direct link to fastifyfastifyinstance-rawserver-rawrequest-requestgeneric-logger")
[src](https://github.com/fastify/fastify/blob/main/types/instance.d.ts#L16)
Interface that represents the Fastify server object. This is the returned server instance from the [`fastify()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method. This type is an interface so it can be extended via [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)
if your code makes use of the `decorate` method.
Through the use of generic cascading, all methods attached to the instance inherit the generic properties from instantiation. This means that by specifying the server, request, or reply types, all methods will know how to type those objects.
Check out the main [Learn by Example](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#learn-by-example)
section for detailed guides, or the more simplified [fastify](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method examples for additional details on this interface.
* * *
#### Request[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#request "Direct link to Request")
##### fastify.FastifyRequest< [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequest-requestgeneric-rawserver-rawrequest "Direct link to fastifyfastifyrequest-requestgeneric-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/request.d.ts#L15)
This interface contains properties of Fastify request object. The properties added here disregard what kind of request object (http vs http2) and disregard what route level it is serving; thus calling `request.body` inside a GET request will not throw an error (but good luck sending a GET request with a body 😉).
If you need to add custom properties to the `FastifyRequest` object (such as when using the \[`decorateRequest`\]\[DecorateRequest\] method) you need to use declaration merging on this interface.
A basic example is provided in the [`FastifyRequest`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
section. For a more detailed example check out the Learn By Example section: [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
###### Example[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example "Direct link to Example")
import fastify from 'fastify'const server = fastify()server.decorateRequest('someProp', 'hello!')server.get('/', async (request, reply) => { const { someProp } = request // need to use declaration merging to add this prop to the request interface return someProp})// this declaration must be in scope of the typescript interpreter to workdeclare module 'fastify' { interface FastifyRequest { // you must reference the interface and not the type someProp: string }}// Or you can type your request usingtype CustomRequest = FastifyRequest<{ Body: { test: boolean };}>server.get('/typedRequest', async (request: CustomRequest, reply: FastifyReply) => { return request.body.test})
##### fastify.RequestGenericInterface[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface "Direct link to fastify.RequestGenericInterface")
[src](https://github.com/fastify/fastify/blob/main/types/request.d.ts#L4)
Fastify request objects have four dynamic properties: `body`, `params`, `query`, and `headers`. Their respective types are assignable through this interface. It is a named property interface enabling the developer to ignore the properties they do not want to specify. All omitted properties are defaulted to `unknown`. The corresponding property names are: `Body`, `Querystring`, `Params`, `Headers`.
import fastify, { RequestGenericInterface } from 'fastify'const server = fastify()interface requestGeneric extends RequestGenericInterface { Querystring: { name: string }}server.get('/', async (request, reply) => { const { name } = request.query // the name prop now exists on the query prop return name.toUpperCase()})
If you want to see a detailed example of using this interface check out the Learn by Example section: [JSON Schema](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#json-schema)
.
##### fastify.RawRequestDefaultExpression< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawrequestdefaultexpression-rawserver "Direct link to fastifyrawrequestdefaultexpression-rawserver")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L23)
Dependent on `@types/node` modules `http`, `https`, `http2`
Generic parameter `RawServer` defaults to [`RawServerDefault`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserverdefault)
If `RawServer` is of type `http.Server` or `https.Server`, then this expression returns `http.IncomingMessage`, otherwise, it returns `http2.Http2ServerRequest`.
import http from 'node:http'import http2 from 'node:http2'import { RawRequestDefaultExpression } from 'fastify'RawRequestDefaultExpression // -> http.IncomingMessageRawRequestDefaultExpression // -> http2.Http2ServerRequest
* * *
#### Reply[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#reply "Direct link to Reply")
##### fastify.FastifyReply< [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreply-requestgeneric-rawserver-rawrequest-rawreply-contextconfig "Direct link to fastifyfastifyreply-requestgeneric-rawserver-rawrequest-rawreply-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/reply.d.ts#L32)
This interface contains the custom properties that Fastify adds to the standard Node.js reply object. The properties added here disregard what kind of reply object (http vs http2).
If you need to add custom properties to the FastifyReply object (such as when using the `decorateReply` method) you need to use declaration merging on this interface.
A basic example is provided in the [`FastifyReply`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
section. For a more detailed example check out the Learn By Example section: [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
###### Example[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-1 "Direct link to Example")
import fastify from 'fastify'const server = fastify()server.decorateReply('someProp', 'world')server.get('/', async (request, reply) => { const { someProp } = reply // need to use declaration merging to add this prop to the reply interface return someProp})// this declaration must be in scope of the typescript interpreter to workdeclare module 'fastify' { interface FastifyReply { // you must reference the interface and not the type someProp: string }}
##### fastify.RawReplyDefaultExpression< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawreplydefaultexpression-rawserver "Direct link to fastifyrawreplydefaultexpression-rawserver")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L27)
Dependent on `@types/node` modules `http`, `https`, `http2`
Generic parameter `RawServer` defaults to [`RawServerDefault`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrawserverdefault)
If `RawServer` is of type `http.Server` or `https.Server`, then this expression returns `http.ServerResponse`, otherwise, it returns `http2.Http2ServerResponse`.
import http from 'node:http'import http2 from 'node:http2'import { RawReplyDefaultExpression } from 'fastify'RawReplyDefaultExpression // -> http.ServerResponseRawReplyDefaultExpression // -> http2.Http2ServerResponse
* * *
#### Plugin[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugin "Direct link to Plugin")
Fastify allows the user to extend its functionalities with plugins. A plugin can be a set of routes, a server decorator or whatever. To activate plugins, use the [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
When creating plugins for Fastify, it is recommended to use the `fastify-plugin` module. Additionally, there is a guide to creating plugins with TypeScript and Fastify available in the Learn by Example, [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
section.
##### fastify.FastifyPluginCallback< [Options](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyplugincallback-options "Direct link to fastifyfastifyplugincallback-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L9)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
##### fastify.FastifyPluginAsync< [Options](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginasync-options "Direct link to fastifyfastifypluginasync-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L20)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
##### fastify.FastifyPlugin< [Options](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyplugin-options "Direct link to fastifyfastifyplugin-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L29)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method. Document deprecated in favor of `FastifyPluginCallback` and `FastifyPluginAsync` since general `FastifyPlugin` doesn't properly infer types for async functions.
##### fastify.FastifyPluginOptions[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions "Direct link to fastify.FastifyPluginOptions")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L31)
A loosely typed object used to constrain the `options` parameter of [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
to an object. When creating a plugin, define its options as an extension of this interface (`interface MyPluginOptions extends FastifyPluginOptions`) so they can be passed to the register method.
* * *
#### Register[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#register "Direct link to Register")
##### fastify.FastifyRegister(plugin: [FastifyPluginCallback](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyplugincallbackoptions)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifyplugincallback-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifyplugincallback-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
##### fastify.FastifyRegister(plugin: [FastifyPluginAsync](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginasyncoptions)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifypluginasync-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifypluginasync-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
##### fastify.FastifyRegister(plugin: [FastifyPlugin](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions-rawserver-rawrequest-requestgeneric)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifyplugin-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifyplugin-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
This type interface specifies the type for the [`fastify.register()`](https://fastify.dev/docs/v5.4.x/Reference/Server/#register)
method. The type interface returns a function signature with an underlying generic `Options` which is defaulted to [FastifyPluginOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifypluginoptions)
. It infers this generic from the FastifyPlugin parameter when calling this function so there is no need to specify the underlying generic. The options parameter is the intersection of the plugin's options and two additional optional properties: `prefix: string` and `logLevel`: [LogLevel](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyloglevel)
. `FastifyPlugin` is deprecated use `FastifyPluginCallback` and `FastifyPluginAsync` instead.
Below is an example of the options inference in action:
const server = fastify()const plugin: FastifyPluginCallback<{ option1: string; option2: boolean;}> = function (instance, opts, done) { }server().register(plugin, {}) // Error - options object is missing required propertiesserver().register(plugin, { option1: '', option2: true }) // OK - options object contains required properties
See the Learn By Example, [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
section for more detailed examples of creating TypeScript plugins in Fastify.
##### fastify.FastifyRegisterOptions[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyregisteroptions "Direct link to fastify.FastifyRegisterOptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L16)
This type is the intersection of the `Options` generic and a non-exported interface `RegisterOptions` that specifies two optional properties: `prefix: string` and `logLevel`: [LogLevel](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyloglevel)
. This type can also be specified as a function that returns the previously described intersection.
* * *
#### Logger[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger-1 "Direct link to Logger")
Check out the [Specifying Logger Types](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#example-5-specifying-logger-types)
example for more details on specifying a custom logger.
##### fastify.FastifyLoggerOptions< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyloggeroptions-rawserver-rawrequest-rawreply "Direct link to fastifyfastifyloggeroptions-rawserver-rawrequest-rawreply")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L17)
An interface definition for the internal Fastify logger. It is emulative of the [Pino.js](https://getpino.io/#/)
logger. When enabled through server options, use it following the general [logger](https://fastify.dev/docs/v5.4.x/Reference/Logging/)
documentation.
##### fastify.FastifyLogFn[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifylogfn "Direct link to fastify.FastifyLogFn")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L7)
An overload function interface that implements the two ways Fastify calls log methods. This interface is passed to all associated log level properties on the FastifyLoggerOptions object.
##### fastify.LogLevel[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyloglevel "Direct link to fastify.LogLevel")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L12)
Union type of: `'info' | 'error' | 'debug' | 'fatal' | 'warn' | 'trace'`
* * *
#### Context[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#context "Direct link to Context")
The context type definition is similar to the other highly dynamic pieces of the type system. Route context is available in the route handler method.
##### fastify.FastifyRequestContext[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestcontext "Direct link to fastify.FastifyRequestContext")
[src](https://github.com/fastify/fastify/blob/main/types/context.d.ts#L11)
An interface with a single required property `config` that is set by default to `unknown`. Can be specified either using a generic or an overload.
This type definition is potentially incomplete. If you are using it and can provide more details on how to improve the definition, we strongly encourage you to open an issue in the main [fastify/fastify](https://github.com/fastify/fastify)
repository. Thank you in advanced!
##### fastify.FastifyReplyContext[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplycontext "Direct link to fastify.FastifyReplyContext")
[src](https://github.com/fastify/fastify/blob/main/types/context.d.ts#L11)
An interface with a single required property `config` that is set by default to `unknown`. Can be specified either using a generic or an overload.
This type definition is potentially incomplete. If you are using it and can provide more details on how to improve the definition, we strongly encourage you to open an issue in the main [fastify/fastify](https://github.com/fastify/fastify)
repository. Thank you in advanced!
* * *
#### Routing[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#routing "Direct link to Routing")
One of the core principles in Fastify is its routing capabilities. Most of the types defined in this section are used under-the-hood by the Fastify instance `.route` and `.get/.post/.etc` methods.
##### fastify.RouteHandlerMethod< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyroutehandlermethod-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyroutehandlermethod-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L105)
A type declaration for the route handler methods. Has two arguments, `request` and `reply` which are typed by `FastifyRequest` and `FastifyReply` respectively. The generics parameters are passed through to these arguments. The method returns either `void` or `Promise` for synchronous and asynchronous handlers respectively.
##### fastify.RouteOptions< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrouteoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L78)
An interface that extends RouteShorthandOptions and adds the following three required properties:
1. `method` which corresponds to a singular [HTTPMethod](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyhttpmethods)
or a list of [HTTPMethods](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyhttpmethods)
2. `url` a string for the route
3. `handler` the route handler method, see \[RouteHandlerMethod\]\[\] for more details
##### fastify.RouteShorthandMethod< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrouteshorthandmethod-rawserver-rawrequest-rawreply "Direct link to fastifyrouteshorthandmethod-rawserver-rawrequest-rawreply")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#12)
An overloaded function interface for three kinds of shorthand route methods to be used in conjunction with the `.get/.post/.etc` methods.
##### fastify.RouteShorthandOptions< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrouteshorthandoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteshorthandoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#55)
An interface that covers all of the base options for a route. Each property on this interface is optional, and it serves as the base for the RouteOptions and RouteShorthandOptionsWithHandler interfaces.
##### fastify.RouteShorthandOptionsWithHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrouteshorthandoptionswithhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteshorthandoptionswithhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#93)
This interface adds a single, required property to the RouteShorthandOptions interface `handler` which is of type RouteHandlerMethod
* * *
#### Parsers[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#parsers "Direct link to Parsers")
##### RawBody[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawbody-1 "Direct link to RawBody")
A generic type that is either a `string` or `Buffer`
##### fastify.FastifyBodyParser< [RawBody](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawbody)
, [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifybodyparser-rawbody-rawserver-rawrequest "Direct link to fastifyfastifybodyparser-rawbody-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L7)
A function type definition for specifying a body parser method. Use the `RawBody` generic to specify the type of the body being parsed.
##### fastify.FastifyContentTypeParser< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifycontenttypeparser-rawserver-rawrequest "Direct link to fastifyfastifycontenttypeparser-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L17)
A function type definition for specifying a body parser method. Content is typed via the `RawRequest` generic.
##### fastify.AddContentTypeParser< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyaddcontenttypeparser-rawserver-rawrequest "Direct link to fastifyaddcontenttypeparser-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L46)
An overloaded interface function definition for the `addContentTypeParser` method. If `parseAs` is passed to the `opts` parameter, the definition uses \[FastifyBodyParser\]\[\] for the `parser` parameter; otherwise, it uses \[FastifyContentTypeParser\]\[\].
##### fastify.hasContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyhascontenttypeparser "Direct link to fastify.hasContentTypeParser")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L63)
A method for checking the existence of a type parser of a certain content type
* * *
#### Errors[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#errors "Direct link to Errors")
##### fastify.FastifyError[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror "Direct link to fastify.FastifyError")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179)
FastifyError is a custom error object that includes status code and validation results.
It extends the Node.js `Error` type, and adds two additional, optional properties: `statusCode: number` and `validation: ValidationResult[]`.
##### fastify.ValidationResult[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyvalidationresult "Direct link to fastify.ValidationResult")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184)
The route validation internally relies upon Ajv, which is a high-performance JSON schema validator.
This interface is passed to instance of FastifyError.
* * *
#### Hooks[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#hooks "Direct link to Hooks")
##### fastify.onRequestHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonrequesthookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonrequesthookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L17)
`onRequest` is the first hook to be executed in the request lifecycle. There was no previous hook, the next hook will be `preParsing`.
Notice: in the `onRequest` hook, request.body will always be null, because the body parsing happens before the `preHandler` hook.
##### fastify.preParsingHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifypreparsinghookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifypreparsinghookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L35)
`preParsing` is the second hook to be executed in the request lifecycle. The previous hook was `onRequest`, the next hook will be `preValidation`.
Notice: in the `preParsing` hook, request.body will always be null, because the body parsing happens before the `preValidation` hook.
Notice: you should also add `receivedEncodedLength` property to the returned stream. This property is used to correctly match the request payload with the `Content-Length` header value. Ideally, this property should be updated on each received chunk.
##### fastify.preValidationHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyprevalidationhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyprevalidationhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L53)
`preValidation` is the third hook to be executed in the request lifecycle. The previous hook was `preParsing`, the next hook will be `preHandler`.
##### fastify.preHandlerHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyprehandlerhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyprehandlerhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L70)
`preHandler` is the fourth hook to be executed in the request lifecycle. The previous hook was `preValidation`, the next hook will be `preSerialization`.
##### fastify.preSerializationHookHandler< PreSerializationPayload, [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, payload: PreSerializationPayload, done: (err: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
| null, res?: unknown) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifypreserializationhookhandler-preserializationpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-preserializationpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void "Direct link to fastifypreserializationhookhandler-preserializationpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-preserializationpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L94)
`preSerialization` is the fifth hook to be executed in the request lifecycle. The previous hook was `preHandler`, the next hook will be `onSend`.
Note: the hook is NOT called if the payload is a string, a Buffer, a stream or null.
##### fastify.onSendHookHandler< OnSendPayload, [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, payload: OnSendPayload, done: (err: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
| null, res?: unknown) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonsendhookhandler-onsendpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-onsendpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void "Direct link to fastifyonsendhookhandler-onsendpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-onsendpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L114)
You can change the payload with the `onSend` hook. It is the sixth hook to be executed in the request lifecycle. The previous hook was `preSerialization`, the next hook will be `onResponse`.
Note: If you change the payload, you may only change it to a string, a Buffer, a stream, or null.
##### fastify.onResponseHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonresponsehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonresponsehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L134)
`onResponse` is the seventh and last hook in the request hook lifecycle. The previous hook was `onSend`, there is no next hook.
The onResponse hook is executed when a response has been sent, so you will not be able to send more data to the client. It can however be useful for sending data to external services, for example to gather statistics.
##### fastify.onErrorHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, error: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
, done: () => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonerrorhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-error-fastifyerror-done---void-promiseunknown--void "Direct link to fastifyonerrorhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-error-fastifyerror-done---void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L154)
This hook is useful if you need to do some custom error logging or add some specific header in case of error.
It is not intended for changing the error, and calling reply.send will throw an exception.
This hook will be executed only after the customErrorHandler has been executed, and only if the customErrorHandler sends an error back to the user (Note that the default customErrorHandler always sends the error back to the user).
Notice: unlike the other hooks, pass an error to the done function is not supported.
##### fastify.onRouteHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#ContextConfigGeneric)
\>(opts: [RouteOptions](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyrouteoptionsrawserver-rawrequest-rawreply-requestgeneric-contextconfig)
& { path: string; prefix: string }): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonroutehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigopts-routeoptions---path-string-prefix-string--promiseunknown--void "Direct link to fastifyonroutehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigopts-routeoptions---path-string-prefix-string--promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L174)
Triggered when a new route is registered. Listeners are passed a routeOptions object as the sole parameter. The interface is synchronous, and, as such, the listener does not get passed a callback
##### fastify.onRegisterHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger)
\>(instance: [FastifyInstance](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyinstance)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonregisterhookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonregisterhookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L191)
Triggered when a new plugin is registered and a new encapsulation context is created. The hook will be executed before the registered code.
This hook can be useful if you are developing a plugin that needs to know when a plugin context is formed, and you want to operate in that specific context.
Note: This hook will not be called if a plugin is wrapped inside fastify-plugin.
##### fastify.onCloseHookHandler< [RawServer](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#logger)
\>(instance: [FastifyInstance](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyinstance)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#fastifyonclosehookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonclosehookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L206)
Triggered when fastify.close() is invoked to stop the server. It is useful when plugins need a "shutdown" event, for example to close an open connection to a database.
* [TypeScript](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#typescript)
* [Learn By Example](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#learn-by-example)
* [Getting Started](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#getting-started)
* [Using Generics](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#using-generics)
* [JSON Schema](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#json-schema)
* [Plugins](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#plugins)
* [Code Completion In Vanilla JavaScript](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#code-completion-in-vanilla-javascript)
* [API Type System Documentation](https://fastify.dev/docs/v5.4.x/Reference/TypeScript/#api-type-system-documentation)
---
# Validation-and-Serialization | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Validation and Serialization[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validation-and-serialization "Direct link to Validation and Serialization")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify uses a schema-based approach. We recommend using [JSON Schema](https://json-schema.org/)
to validate routes and serialize outputs. Fastify compiles the schema into a highly performant function.
Validation is only attempted if the content type is `application/json`.
All examples use the [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7)
specification.
> ⚠ Warning: Treat schema definitions as application code. Validation and serialization features use `new Function()`, which is unsafe with user-provided schemas. See [Ajv](https://npm.im/ajv)
> and [fast-json-stringify](https://npm.im/fast-json-stringify)
> for details.
>
> Whilst Fastify supports the [`$async` Ajv feature](https://ajv.js.org/guide/async-validation.html)
> , it should not be used for initial validation. Accessing databases during validation may lead to Denial of Service attacks. Use [Fastify's hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/)
> like `preHandler` for `async` tasks after validation.
### Core concepts[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#core-concepts "Direct link to Core concepts")
Validation and serialization are handled by two customizable dependencies:
* [Ajv v8](https://www.npmjs.com/package/ajv)
for request validation
* [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
for response body serialization
These dependencies share only the JSON schemas added to Fastify's instance via `.addSchema(schema)`.
#### Adding a shared schema[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#adding-a-shared-schema "Direct link to Adding a shared schema")
The `addSchema` API allows adding multiple schemas to the Fastify instance for reuse throughout the application. This API is encapsulated.
Shared schemas can be reused with the JSON Schema [**`$ref`**](https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8)
keyword. Here is an overview of how references work:
* `myField: { $ref: '#foo' }` searches for `$id: '#foo'` in the current schema
* `myField: { $ref: '#/definitions/foo' }` searches for `definitions.foo` in the current schema
* `myField: { $ref: 'http://url.com/sh.json#' }` searches for a shared schema with `$id: 'http://url.com/sh.json'`
* `myField: { $ref: 'http://url.com/sh.json#/definitions/foo' }` searches for a shared schema with `$id: 'http://url.com/sh.json'` and uses `definitions.foo`
* `myField: { $ref: 'http://url.com/sh.json#foo' }` searches for a shared schema with `$id: 'http://url.com/sh.json'` and looks for `$id: '#foo'` within it
**Simple usage:**
fastify.addSchema({ $id: 'http://example.com/', type: 'object', properties: { hello: { type: 'string' } }})fastify.post('/', { handler () {}, schema: { body: { type: 'array', items: { $ref: 'http://example.com#/properties/hello' } } }})
**`$ref` as root reference:**
fastify.addSchema({ $id: 'commonSchema', type: 'object', properties: { hello: { type: 'string' } }})fastify.post('/', { handler () {}, schema: { body: { $ref: 'commonSchema#' }, headers: { $ref: 'commonSchema#' } }})
#### Retrieving the shared schemas[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#retrieving-the-shared-schemas "Direct link to Retrieving the shared schemas")
If the validator and serializer are customized, `.addSchema` is not useful since Fastify no longer controls them. To access schemas added to the Fastify instance, use `.getSchemas()`:
fastify.addSchema({ $id: 'schemaId', type: 'object', properties: { hello: { type: 'string' } }})const mySchemas = fastify.getSchemas()const mySchema = fastify.getSchema('schemaId')
The `getSchemas` function is encapsulated and returns shared schemas available in the selected scope:
fastify.addSchema({ $id: 'one', my: 'hello' })// will return only `one` schemafastify.get('/', (request, reply) => { reply.send(fastify.getSchemas()) })fastify.register((instance, opts, done) => { instance.addSchema({ $id: 'two', my: 'ciao' }) // will return `one` and `two` schemas instance.get('/sub', (request, reply) => { reply.send(instance.getSchemas()) }) instance.register((subinstance, opts, done) => { subinstance.addSchema({ $id: 'three', my: 'hola' }) // will return `one`, `two` and `three` subinstance.get('/deep', (request, reply) => { reply.send(subinstance.getSchemas()) }) done() }) done()})
### Validation[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validation "Direct link to Validation")
Route validation relies on [Ajv v8](https://www.npmjs.com/package/ajv)
, a high-performance JSON Schema validator. To validate input, add the required fields to the route schema.
Supported validations include:
* `body`: validates the request body for POST, PUT, or PATCH methods.
* `querystring` or `query`: validates the query string.
* `params`: validates the route parameters.
* `headers`: validates the request headers.
Validations can be a complete JSON Schema object with a `type` of `'object'` and a `'properties'` object containing parameters, or a simpler variation listing parameters at the top level.
> ℹ For using the latest Ajv (v8), refer to the [`schemaController`](https://fastify.dev/docs/v5.4.x/Reference/Server/#schema-controller)
> section.
Example:
const bodyJsonSchema = { type: 'object', required: ['requiredKey'], properties: { someKey: { type: 'string' }, someOtherKey: { type: 'number' }, requiredKey: { type: 'array', maxItems: 3, items: { type: 'integer' } }, nullableKey: { type: ['number', 'null'] }, // or { type: 'number', nullable: true } multipleTypesKey: { type: ['boolean', 'number'] }, multipleRestrictedTypesKey: { oneOf: [ { type: 'string', maxLength: 5 }, { type: 'number', minimum: 10 } ] }, enumKey: { type: 'string', enum: ['John', 'Foo'] }, notTypeKey: { not: { type: 'array' } } }}const queryStringJsonSchema = { type: 'object', properties: { name: { type: 'string' }, excitement: { type: 'integer' } }}const paramsJsonSchema = { type: 'object', properties: { par1: { type: 'string' }, par2: { type: 'number' } }}const headersJsonSchema = { type: 'object', properties: { 'x-foo': { type: 'string' } }, required: ['x-foo']}const schema = { body: bodyJsonSchema, querystring: queryStringJsonSchema, params: paramsJsonSchema, headers: headersJsonSchema}fastify.post('/the/url', { schema }, handler)
For `body` schema, it is further possible to differentiate the schema per content type by nesting the schemas inside `content` property. The schema validation will be applied based on the `Content-Type` header in the request.
fastify.post('/the/url', { schema: { body: { content: { 'application/json': { schema: { type: 'object' } }, 'text/plain': { schema: { type: 'string' } } // Other content types will not be validated } } }}, handler)
Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html)
values to the types specified in the schema `type` keywords, both to pass validation and to use the correctly typed data afterwards.
The Ajv default configuration in Fastify supports coercing array parameters in `querystring`. Example:
const opts = { schema: { querystring: { type: 'object', properties: { ids: { type: 'array', default: [] }, }, } }}fastify.get('/', opts, (request, reply) => { reply.send({ params: request.query }) // echo the querystring})fastify.listen({ port: 3000 }, (err) => { if (err) throw err})
curl -X GET "http://localhost:3000/?ids=1{"params":{"ids":["1"]}}
A custom schema validator can be specified for each parameter type (body, querystring, params, headers).
For example, the following code disables type coercion only for the `body` parameters, changing the Ajv default options:
const schemaCompilers = { body: new Ajv({ removeAdditional: false, coerceTypes: false, allErrors: true }), params: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true }), querystring: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true }), headers: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true })}server.setValidatorCompiler(req => { if (!req.httpPart) { throw new Error('Missing httpPart') } const compiler = schemaCompilers[req.httpPart] if (!compiler) { throw new Error(`Missing compiler for ${req.httpPart}`) } return compiler.compile(req.schema)})
For more information, see [Ajv Coercion](https://ajv.js.org/coercion.html)
.
#### Ajv Plugins[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#ajv-plugins "Direct link to Ajv Plugins")
A list of plugins can be provided for use with the default `ajv` instance. Ensure the plugin is **compatible with the Ajv version shipped within Fastify**.
> Refer to [`ajv options`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ajv)
> to check plugins format.
const fastify = require('fastify')({ ajv: { plugins: [ require('ajv-merge-patch') ] }})fastify.post('/', { handler (req, reply) { reply.send({ ok: 1 }) }, schema: { body: { $patch: { source: { type: 'object', properties: { q: { type: 'string' } } }, with: [ { op: 'add', path: '/properties/q', value: { type: 'number' } } ] } } }})fastify.post('/foo', { handler (req, reply) { reply.send({ ok: 1 }) }, schema: { body: { $merge: { source: { type: 'object', properties: { q: { type: 'string' } } }, with: { required: ['q'] } } } }})
#### Validator Compiler[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validator-compiler "Direct link to Validator Compiler")
The `validatorCompiler` is a function that returns a function to validate the body, URL parameters, headers, and query string. The default `validatorCompiler` returns a function that implements the [ajv](https://ajv.js.org/)
validation interface. Fastify uses it internally to speed up validation.
Fastify's [baseline ajv configuration](https://github.com/fastify/ajv-compiler#ajv-configuration)
is:
{ coerceTypes: 'array', // change data type of data to match type keyword useDefaults: true, // replace missing properties and items with the values from corresponding default keyword removeAdditional: true, // remove additional properties if additionalProperties is set to false, see: https://ajv.js.org/guide/modifying-data.html#removing-additional-properties uriResolver: require('fast-uri'), addUsedSchema: false, // Explicitly set allErrors to `false`. // When set to `true`, a DoS attack is possible. allErrors: false}
Modify the baseline configuration by providing [`ajv.customOptions`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-ajv)
to the Fastify factory.
To change or set additional config options, create a custom instance and override the existing one:
const fastify = require('fastify')()const Ajv = require('ajv')const ajv = new Ajv({ removeAdditional: 'all', useDefaults: true, coerceTypes: 'array', // any other options // ...})fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => { return ajv.compile(schema)})
> ℹ️ Note: When using a custom validator instance, add schemas to the validator instead of Fastify. Fastify's `addSchema` method will not recognize the custom validator.
##### Using other validation libraries[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#using-other-validation-libraries "Direct link to Using other validation libraries")
The `setValidatorCompiler` function allows substituting `ajv` with other JavaScript validation libraries like [joi](https://github.com/hapijs/joi/)
or [yup](https://github.com/jquense/yup/)
, or a custom one:
const Joi = require('joi')fastify.post('/the/url', { schema: { body: Joi.object().keys({ hello: Joi.string().required() }).required() }, validatorCompiler: ({ schema, method, url, httpPart }) => { return data => schema.validate(data) }}, handler)
const yup = require('yup')// Validation options to match ajv's baseline options used in Fastifyconst yupOptions = { strict: false, abortEarly: false, // return all errors stripUnknown: true, // remove additional properties recursive: true}fastify.post('/the/url', { schema: { body: yup.object({ age: yup.number().integer().required(), sub: yup.object().shape({ name: yup.string().required() }).required() }) }, validatorCompiler: ({ schema, method, url, httpPart }) => { return function (data) { // with option strict = false, yup `validateSync` function returns the // coerced value if validation was successful, or throws if validation failed try { const result = schema.validateSync(data, yupOptions) return { value: result } } catch (e) { return { error: e } } } }}, handler)
##### .statusCode property[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#statuscode-property "Direct link to .statusCode property")
All validation errors have a `.statusCode` property set to `400`, ensuring the default error handler sets the response status code to `400`.
fastify.setErrorHandler(function (error, request, reply) { request.log.error(error, `This error has status code ${error.statusCode}`) reply.status(error.statusCode).send(error)})
##### Validation messages with other validation libraries[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validation-messages-with-other-validation-libraries "Direct link to Validation messages with other validation libraries")
Fastify's validation error messages are tightly coupled to the default validation engine: errors returned from `ajv` are eventually run through the `schemaErrorFormatter` function which builds human-friendly error messages. However, the `schemaErrorFormatter` function is written with `ajv` in mind. This may result in odd or incomplete error messages when using other validation libraries.
To circumvent this issue, there are two main options:
1. Ensure the validation function (returned by the custom `schemaCompiler`) returns errors in the same structure and format as `ajv`.
2. Use a custom `errorHandler` to intercept and format custom validation errors.
Fastify adds two properties to all validation errors to help write a custom `errorHandler`:
* `validation`: the content of the `error` property of the object returned by the validation function (returned by the custom `schemaCompiler`)
* `validationContext`: the context (body, params, query, headers) where the validation error occurred
A contrived example of such a custom `errorHandler` handling validation errors is shown below:
const errorHandler = (error, request, reply) => { const statusCode = error.statusCode let response const { validation, validationContext } = error // check if we have a validation error if (validation) { response = { // validationContext will be 'body', 'params', 'headers', or 'query' message: `A validation error occurred when validating the ${validationContext}...`, // this is the result of the validation library... errors: validation } } else { response = { message: 'An error occurred...' } } // any additional work here, eg. log error // ... reply.status(statusCode).send(response)}
### Serialization[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#serialization "Direct link to Serialization")
Fastify uses [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
to send data as JSON if an output schema is provided in the route options. Using an output schema can drastically increase throughput and help prevent accidental disclosure of sensitive information.
Example:
const schema = { response: { 200: { type: 'object', properties: { value: { type: 'string' }, otherValue: { type: 'boolean' } } } }}fastify.post('/the/url', { schema }, handler)
The response schema is based on the status code. To use the same schema for multiple status codes, use `'2xx'` or `default`, for example:
const schema = { response: { default: { type: 'object', properties: { error: { type: 'boolean', default: true } } }, '2xx': { type: 'object', properties: { value: { type: 'string' }, otherValue: { type: 'boolean' } } }, 201: { // the contract syntax value: { type: 'string' } } }}fastify.post('/the/url', { schema }, handler)
A specific response schema can be defined for different content types. For example:
const schema = { response: { 200: { description: 'Response schema that support different content types' content: { 'application/json': { schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } }, 'application/vnd.v1+json': { schema: { type: 'array', items: { $ref: 'test' } } } } }, '3xx': { content: { 'application/vnd.v2+json': { schema: { fullName: { type: 'string' }, phone: { type: 'string' } } } } }, default: { content: { // */* is match-all content-type '*/*': { schema: { desc: { type: 'string' } } } } } }}fastify.post('/url', { schema }, handler)
#### Serializer Compiler[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#serializer-compiler "Direct link to Serializer Compiler")
The `serializerCompiler` returns a function that must return a string from an input object. When defining a response JSON Schema, change the default serialization method by providing a function to serialize each route.
fastify.setSerializerCompiler(({ schema, method, url, httpStatus, contentType }) => { return data => JSON.stringify(data)})fastify.get('/user', { handler (req, reply) { reply.send({ id: 1, name: 'Foo', image: 'BIG IMAGE' }) }, schema: { response: { '2xx': { type: 'object', properties: { id: { type: 'number' }, name: { type: 'string' } } } } }})
_To set a custom serializer in a specific part of the code, use [`reply.serializer(...)`](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializerfunc)
._
### Error Handling[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#error-handling "Direct link to Error Handling")
When schema validation fails for a request, Fastify will automatically return a status 400 response including the result from the validator in the payload. For example, if the following schema is used for a route:
const schema = { body: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }}
If the request fails to satisfy the schema, the route will return a response with the following payload:
{ "statusCode": 400, "error": "Bad Request", "message": "body should have required property 'name'"}
To handle errors inside the route, specify the `attachValidation` option. If there is a validation error, the `validationError` property of the request will contain the `Error` object with the raw validation result as shown below:
const fastify = Fastify()fastify.post('/', { schema, attachValidation: true }, function (req, reply) { if (req.validationError) { // `req.validationError.validation` contains the raw validation error reply.code(400).send(req.validationError) }})
#### `schemaErrorFormatter`[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schemaerrorformatter "Direct link to schemaerrorformatter")
To format errors, provide a sync function that returns an error as the `schemaErrorFormatter` option when instantiating Fastify. The context function will be the Fastify server instance.
`errors` is an array of Fastify schema errors `FastifySchemaValidationError`. `dataVar` is the currently validated part of the schema (params, body, querystring, headers).
const fastify = Fastify({ schemaErrorFormatter: (errors, dataVar) => { // ... my formatting logic return new Error(myErrorMessage) }})// orfastify.setSchemaErrorFormatter(function (errors, dataVar) { this.log.error({ err: errors }, 'Validation failed') // ... my formatting logic return new Error(myErrorMessage)})
Use [setErrorHandler](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
to define a custom response for validation errors such as:
fastify.setErrorHandler(function (error, request, reply) { if (error.validation) { reply.status(422).send(new Error('validation failed')) }})
For custom error responses in the schema, see [`ajv-errors`](https://github.com/epoberezkin/ajv-errors)
. Check out the [example](https://github.com/fastify/example/blob/HEAD/validation-messages/custom-errors-messages.js)
usage.
> Install version 1.0.1 of `ajv-errors`, as later versions are not compatible with AJV v6 (the version shipped by Fastify v3).
Below is an example showing how to add **custom error messages for each property** of a schema by supplying custom AJV options. Inline comments in the schema describe how to configure it to show a different error message for each case:
const fastify = Fastify({ ajv: { customOptions: { jsonPointers: true, // ⚠ Warning: Enabling this option may lead to this security issue https://www.cvedetails.com/cve/CVE-2020-8192/ allErrors: true }, plugins: [ require('ajv-errors') ] }})const schema = { body: { type: 'object', properties: { name: { type: 'string', errorMessage: { type: 'Bad name' } }, age: { type: 'number', errorMessage: { type: 'Bad age', // specify custom message for min: 'Too young' // all constraints except required } } }, required: ['name', 'age'], errorMessage: { required: { name: 'Why no name!', // specify error message for when the age: 'Why no age!' // property is missing from input } } }}fastify.post('/', { schema, }, (request, reply) => { reply.send({ hello: 'world' })})
To return localized error messages, see [ajv-i18n](https://github.com/epoberezkin/ajv-i18n)
.
const localize = require('ajv-i18n')const fastify = Fastify()const schema = { body: { type: 'object', properties: { name: { type: 'string', }, age: { type: 'number', } }, required: ['name', 'age'], }}fastify.setErrorHandler(function (error, request, reply) { if (error.validation) { localize.ru(error.validation) reply.status(400).send(error.validation) return } reply.send(error)})
### JSON Schema support[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#json-schema-support "Direct link to JSON Schema support")
JSON Schema provides utilities to optimize schemas. Combined with Fastify's shared schema, all schemas can be easily reused.
| Use Case | Validator | Serializer |
| --- | --- | --- |
| `$ref` to `$id` | ️️✔️ | ✔️ |
| `$ref` to `/definitions` | ✔️ | ✔️ |
| `$ref` to shared schema `$id` | ✔️ | ✔️ |
| `$ref` to shared schema `/definitions` | ✔️ | ✔️ |
#### Examples[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#examples "Direct link to Examples")
##### Usage of `$ref` to `$id` in same JSON Schema[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#usage-of-ref-to-id-in-same-json-schema "Direct link to usage-of-ref-to-id-in-same-json-schema")
const refToId = { type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }, properties: { home: { $ref: '#address' }, work: { $ref: '#address' } }}
##### Usage of `$ref` to `/definitions` in same JSON Schema[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#usage-of-ref-to-definitions-in-same-json-schema "Direct link to usage-of-ref-to-definitions-in-same-json-schema")
const refToDefinitions = { type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }, properties: { home: { $ref: '#/definitions/foo' }, work: { $ref: '#/definitions/foo' } }}
##### Usage `$ref` to a shared schema `$id` as external schema[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#usage-ref-to-a-shared-schema-id-as-external-schema "Direct link to usage-ref-to-a-shared-schema-id-as-external-schema")
fastify.addSchema({ $id: 'http://foo/common.json', type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }})const refToSharedSchemaId = { type: 'object', properties: { home: { $ref: 'http://foo/common.json#address' }, work: { $ref: 'http://foo/common.json#address' } }}
##### Usage `$ref` to a shared schema `/definitions` as external schema[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#usage-ref-to-a-shared-schema-definitions-as-external-schema "Direct link to usage-ref-to-a-shared-schema-definitions-as-external-schema")
fastify.addSchema({ $id: 'http://foo/shared.json', type: 'object', definitions: { foo: { type: 'object', properties: { city: { type: 'string' } } } }})const refToSharedSchemaDefinitions = { type: 'object', properties: { home: { $ref: 'http://foo/shared.json#/definitions/foo' }, work: { $ref: 'http://foo/shared.json#/definitions/foo' } }}
### Resources[](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#resources "Direct link to Resources")
* [JSON Schema](https://json-schema.org/)
* [Understanding JSON Schema](https://spacetelescope.github.io/understanding-json-schema/)
* [fast-json-stringify documentation](https://github.com/fastify/fast-json-stringify)
* [Ajv documentation](https://github.com/epoberezkin/ajv/blob/master/README.md)
* [Ajv i18n](https://github.com/epoberezkin/ajv-i18n)
* [Ajv custom errors](https://github.com/epoberezkin/ajv-errors)
* Custom error handling with core methods with error file dumping [example](https://github.com/fastify/example/tree/main/validation-messages)
* [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validation-and-serialization)
* [Core concepts](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#core-concepts)
* [Validation](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#validation)
* [Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#serialization)
* [Error Handling](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#error-handling)
* [JSON Schema support](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#json-schema-support)
* [Resources](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#resources)
---
# Server | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Server/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
Factory[](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory "Direct link to Factory")
-----------------------------------------------------------------------------------------------
The Fastify module exports a factory function that is used to create new `**Fastify server**` instances. This factory function accepts an options object which is used to customize the resulting instance. This document describes the properties available in that options object.
* [Factory](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory)
* [`http`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http)
* [`http2`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2)
* [`https`](https://fastify.dev/docs/v5.4.x/Reference/Server/#https)
* [`connectionTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#connectiontimeout)
* [`keepAliveTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#keepalivetimeout)
* [`forceCloseConnections`](https://fastify.dev/docs/v5.4.x/Reference/Server/#forcecloseconnections)
* [`maxRequestsPerSocket`](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxrequestspersocket)
* [`requestTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requesttimeout)
* [`ignoreTrailingSlash`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoretrailingslash)
* [`ignoreDuplicateSlashes`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoreduplicateslashes)
* [`maxParamLength`](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxparamlength)
* [`bodyLimit`](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit)
* [`onProtoPoisoning`](https://fastify.dev/docs/v5.4.x/Reference/Server/#onprotopoisoning)
* [`onConstructorPoisoning`](https://fastify.dev/docs/v5.4.x/Reference/Server/#onconstructorpoisoning)
* [`logger`](https://fastify.dev/docs/v5.4.x/Reference/Server/#logger)
* [`loggerInstance`](https://fastify.dev/docs/v5.4.x/Reference/Server/#loggerInstance)
* [`disableRequestLogging`](https://fastify.dev/docs/v5.4.x/Reference/Server/#disablerequestlogging)
* [`serverFactory`](https://fastify.dev/docs/v5.4.x/Reference/Server/#serverfactory)
* [`caseSensitive`](https://fastify.dev/docs/v5.4.x/Reference/Server/#casesensitive)
* [`allowUnsafeRegex`](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowunsaferegex)
* [`requestIdHeader`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidheader)
* [`requestIdLogLabel`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidloglabel)
* [`genReqId`](https://fastify.dev/docs/v5.4.x/Reference/Server/#genreqid)
* [`trustProxy`](https://fastify.dev/docs/v5.4.x/Reference/Server/#trustproxy)
* [`pluginTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#plugintimeout)
* [`querystringParser`](https://fastify.dev/docs/v5.4.x/Reference/Server/#querystringparser)
* [`exposeHeadRoutes`](https://fastify.dev/docs/v5.4.x/Reference/Server/#exposeheadroutes)
* [`constraints`](https://fastify.dev/docs/v5.4.x/Reference/Server/#constraints)
* [`return503OnClosing`](https://fastify.dev/docs/v5.4.x/Reference/Server/#return503onclosing)
* [`ajv`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ajv)
* [`serializerOpts`](https://fastify.dev/docs/v5.4.x/Reference/Server/#serializeropts)
* [`http2SessionTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2sessiontimeout)
* [`frameworkErrors`](https://fastify.dev/docs/v5.4.x/Reference/Server/#frameworkerrors)
* [`clientErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#clienterrorhandler)
* [`rewriteUrl`](https://fastify.dev/docs/v5.4.x/Reference/Server/#rewriteurl)
* [`useSemicolonDelimiter`](https://fastify.dev/docs/v5.4.x/Reference/Server/#usesemicolondelimiter)
* [`allowErrorHandlerOverride`](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowerrorhandleroverride)
* [Instance](https://fastify.dev/docs/v5.4.x/Reference/Server/#instance)
* [Server Methods](https://fastify.dev/docs/v5.4.x/Reference/Server/#server-methods)
* [server](https://fastify.dev/docs/v5.4.x/Reference/Server/#server)
* [after](https://fastify.dev/docs/v5.4.x/Reference/Server/#after)
* [ready](https://fastify.dev/docs/v5.4.x/Reference/Server/#ready)
* [listen](https://fastify.dev/docs/v5.4.x/Reference/Server/#listen)
* [`listenTextResolver`](https://fastify.dev/docs/v5.4.x/Reference/Server/#listentextresolver)
* [addresses](https://fastify.dev/docs/v5.4.x/Reference/Server/#addresses)
* [routing](https://fastify.dev/docs/v5.4.x/Reference/Server/#routing)
* [route](https://fastify.dev/docs/v5.4.x/Reference/Server/#route)
* [hasRoute](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasroute)
* [findRoute](https://fastify.dev/docs/v5.4.x/Reference/Server/#findroute)
* [close](https://fastify.dev/docs/v5.4.x/Reference/Server/#close)
* [decorate\*](https://fastify.dev/docs/v5.4.x/Reference/Server/#decorate)
* [register](https://fastify.dev/docs/v5.4.x/Reference/Server/#register)
* [addHook](https://fastify.dev/docs/v5.4.x/Reference/Server/#addhook)
* [prefix](https://fastify.dev/docs/v5.4.x/Reference/Server/#prefix)
* [pluginName](https://fastify.dev/docs/v5.4.x/Reference/Server/#pluginname)
* [hasPlugin](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasplugin)
* [listeningOrigin](https://fastify.dev/docs/v5.4.x/Reference/Server/#listeningorigin)
* [log](https://fastify.dev/docs/v5.4.x/Reference/Server/#log)
* [version](https://fastify.dev/docs/v5.4.x/Reference/Server/#version)
* [inject](https://fastify.dev/docs/v5.4.x/Reference/Server/#inject)
* [addHttpMethod](https://fastify.dev/docs/v5.4.x/Reference/Server/#addHttpMethod)
* [addSchema](https://fastify.dev/docs/v5.4.x/Reference/Server/#addschema)
* [getSchemas](https://fastify.dev/docs/v5.4.x/Reference/Server/#getschemas)
* [getSchema](https://fastify.dev/docs/v5.4.x/Reference/Server/#getschema)
* [setReplySerializer](https://fastify.dev/docs/v5.4.x/Reference/Server/#setreplyserializer)
* [setValidatorCompiler](https://fastify.dev/docs/v5.4.x/Reference/Server/#setvalidatorcompiler)
* [setSchemaErrorFormatter](https://fastify.dev/docs/v5.4.x/Reference/Server/#setschemaerrorformatter)
* [setSerializerCompiler](https://fastify.dev/docs/v5.4.x/Reference/Server/#setserializercompiler)
* [validatorCompiler](https://fastify.dev/docs/v5.4.x/Reference/Server/#validatorcompiler)
* [serializerCompiler](https://fastify.dev/docs/v5.4.x/Reference/Server/#serializercompiler)
* [schemaErrorFormatter](https://fastify.dev/docs/v5.4.x/Reference/Server/#schemaerrorformatter)
* [schemaController](https://fastify.dev/docs/v5.4.x/Reference/Server/#schemacontroller)
* [setNotFoundHandler](https://fastify.dev/docs/v5.4.x/Reference/Server/#setnotfoundhandler)
* [setErrorHandler](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
* [setChildLoggerFactory](https://fastify.dev/docs/v5.4.x/Reference/Server/#setchildloggerfactory)
* [setGenReqId](https://fastify.dev/docs/v5.4.x/Reference/Server/#setGenReqId)
* [addConstraintStrategy](https://fastify.dev/docs/v5.4.x/Reference/Server/#addconstraintstrategy)
* [hasConstraintStrategy](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasconstraintstrategy)
* [printRoutes](https://fastify.dev/docs/v5.4.x/Reference/Server/#printroutes)
* [printPlugins](https://fastify.dev/docs/v5.4.x/Reference/Server/#printplugins)
* [addContentTypeParser](https://fastify.dev/docs/v5.4.x/Reference/Server/#addcontenttypeparser)
* [hasContentTypeParser](https://fastify.dev/docs/v5.4.x/Reference/Server/#hascontenttypeparser)
* [removeContentTypeParser](https://fastify.dev/docs/v5.4.x/Reference/Server/#removecontenttypeparser)
* [removeAllContentTypeParsers](https://fastify.dev/docs/v5.4.x/Reference/Server/#removeallcontenttypeparsers)
* [getDefaultJsonParser](https://fastify.dev/docs/v5.4.x/Reference/Server/#getdefaultjsonparser)
* [defaultTextParser](https://fastify.dev/docs/v5.4.x/Reference/Server/#defaulttextparser)
* [errorHandler](https://fastify.dev/docs/v5.4.x/Reference/Server/#errorhandler)
* [childLoggerFactory](https://fastify.dev/docs/v5.4.x/Reference/Server/#childloggerfactory)
* [Symbol.asyncDispose](https://fastify.dev/docs/v5.4.x/Reference/Server/#symbolasyncdispose)
* [initialConfig](https://fastify.dev/docs/v5.4.x/Reference/Server/#initialconfig)
### `http`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#http "Direct link to http")
* Default: `null`
An object used to configure the server's listening socket. The options are the same as the Node.js core [`createServer` method](https://nodejs.org/docs/latest-v20.x/api/http.html#httpcreateserveroptions-requestlistener)
.
This option is ignored if options [`http2`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-http2)
or [`https`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-https)
are set.
### `http2`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2 "Direct link to http2")
* Default: `false`
If `true` Node.js core's [HTTP/2](https://nodejs.org/dist/latest-v20.x/docs/api/http2.html)
module is used for binding the socket.
### `https`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#https "Direct link to https")
* Default: `null`
An object used to configure the server's listening socket for TLS. The options are the same as the Node.js core [`createServer` method](https://nodejs.org/dist/latest-v20.x/docs/api/https.html#https_https_createserver_options_requestlistener)
. When this property is `null`, the socket will not be configured for TLS.
This option also applies when the [`http2`](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-http2)
option is set.
### `connectionTimeout`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#connectiontimeout "Direct link to connectiontimeout")
* Default: `0` (no timeout)
Defines the server timeout in milliseconds. See documentation for [`server.timeout` property](https://nodejs.org/api/http.html#http_server_timeout)
to understand the effect of this option.
When `serverFactory` option is specified this option is ignored.
### `keepAliveTimeout`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#keepalivetimeout "Direct link to keepalivetimeout")
* Default: `72000` (72 seconds)
Defines the server keep-alive timeout in milliseconds. See documentation for [`server.keepAliveTimeout` property](https://nodejs.org/api/http.html#http_server_keepalivetimeout)
to understand the effect of this option. This option only applies when HTTP/1 is in use.
When `serverFactory` option is specified this option is ignored.
### `forceCloseConnections`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#forcecloseconnections "Direct link to forcecloseconnections")
* Default: `"idle"` if the HTTP server allows it, `false` otherwise
When set to `true`, upon [`close`](https://fastify.dev/docs/v5.4.x/Reference/Server/#close)
the server will iterate the current persistent connections and [destroy their sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror)
.
> ⚠ Warning: Connections are not inspected to determine if requests have been completed.
Fastify will prefer the HTTP server's [`closeAllConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseallconnections)
method if supported, otherwise, it will use internal connection tracking.
When set to `"idle"`, upon [`close`](https://fastify.dev/docs/v5.4.x/Reference/Server/#close)
the server will iterate the current persistent connections which are not sending a request or waiting for a response and destroy their sockets. The value is only supported if the HTTP server supports the [`closeIdleConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseidleconnections)
method, otherwise attempting to set it will throw an exception.
### `maxRequestsPerSocket`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxrequestspersocket "Direct link to maxrequestspersocket")
* Default: `0` (no limit)
Defines the maximum number of requests a socket can handle before closing keep alive connection. See [`server.maxRequestsPerSocket` property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_maxrequestspersocket)
to understand the effect of this option. This option only applies when HTTP/1.1 is in use. Also, when `serverFactory` option is specified, this option is ignored.
> ℹ️ Note: At the time of writing, only node >= v16.10.0 supports this option.
### `requestTimeout`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#requesttimeout "Direct link to requesttimeout")
* Default: `0` (no limit)
Defines the maximum number of milliseconds for receiving the entire request from the client. See [`server.requestTimeout` property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
to understand the effect of this option.
When `serverFactory` option is specified, this option is ignored. It must be set to a non-zero value (e.g. 120 seconds) to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front.
> ℹ️ Note: At the time of writing, only node >= v14.11.0 supports this option
### `ignoreTrailingSlash`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoretrailingslash "Direct link to ignoretrailingslash")
* Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
to handle routing. By default, Fastify will take into account the trailing slashes. Paths like `/foo` and `/foo/` are treated as different paths. If you want to change this, set this flag to `true`. That way, both `/foo` and `/foo/` will point to the same route. This option applies to _all_ route registrations for the resulting server instance.
const fastify = require('fastify')({ ignoreTrailingSlash: true})// registers both "/foo" and "/foo/"fastify.get('/foo/', function (req, reply) { reply.send('foo')})// registers both "/bar" and "/bar/"fastify.get('/bar', function (req, reply) { reply.send('bar')})
### `ignoreDuplicateSlashes`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoreduplicateslashes "Direct link to ignoreduplicateslashes")
* Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
to handle routing. You can use `ignoreDuplicateSlashes` option to remove duplicate slashes from the path. It removes duplicate slashes in the route path and the request URL. This option applies to _all_ route registrations for the resulting server instance.
When `ignoreTrailingSlash` and `ignoreDuplicateSlashes` are both set to `true` Fastify will remove duplicate slashes, and then trailing slashes, meaning `//a//b//c//` will be converted to `/a/b/c`.
const fastify = require('fastify')({ ignoreDuplicateSlashes: true})// registers "/foo/bar/"fastify.get('///foo//bar//', function (req, reply) { reply.send('foo')})
### `maxParamLength`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxparamlength "Direct link to maxparamlength")
* Default: `100`
You can set a custom length for parameters in parametric (standard, regex, and multi) routes by using `maxParamLength` option; the default value is 100 characters. If the maximum length limit is reached, the not found route will be invoked.
This can be useful especially if you have a regex-based route, protecting you against [ReDoS attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS)
.
### `bodyLimit`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit "Direct link to bodylimit")
* Default: `1048576` (1MiB)
Defines the maximum payload, in bytes, the server is allowed to accept. The default body reader sends [`FST_ERR_CTP_BODY_TOO_LARGE`](https://fastify.dev/docs/v5.4.x/Reference/Errors/#fst_err_ctp_body_too_large)
reply, if the size of the body exceeds this limit. If [`preParsing` hook](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#preparsing)
is provided, this limit is applied to the size of the stream the hook returns (i.e. the size of "decoded" body).
### `onProtoPoisoning`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#onprotopoisoning "Direct link to onprotopoisoning")
* Default: `'error'`
Defines what action the framework must take when parsing a JSON object with `__proto__`. This functionality is provided by [secure-json-parse](https://github.com/fastify/secure-json-parse)
. See [Prototype Poisoning](https://fastify.dev/docs/v5.4.x/Guides/Prototype-Poisoning/)
for more details about prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `onConstructorPoisoning`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#onconstructorpoisoning "Direct link to onconstructorpoisoning")
* Default: `'error'`
Defines what action the framework must take when parsing a JSON object with `constructor`. This functionality is provided by [secure-json-parse](https://github.com/fastify/secure-json-parse)
. See [Prototype Poisoning](https://fastify.dev/docs/v5.4.x/Guides/Prototype-Poisoning/)
for more details about prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `logger`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#logger "Direct link to logger")
Fastify includes built-in logging via the [Pino](https://getpino.io/)
logger. This property is used to configure the internal logger instance.
The possible values this property may have are:
* Default: `false`. The logger is disabled. All logging methods will point to a null logger [abstract-logging](https://npm.im/abstract-logging)
instance.
* `object`: a standard Pino [options object](https://github.com/pinojs/pino/blob/c77d8ec5ce/docs/API.md#constructor)
. This will be passed directly to the Pino constructor. If the following properties are not present on the object, they will be added accordingly:
* `level`: the minimum logging level. If not set, it will be set to `'info'`.
* `serializers`: a hash of serialization functions. By default, serializers are added for `req` (incoming request objects), `res` (outgoing response objects), and `err` (standard `Error` objects). When a log method receives an object with any of these properties then the respective serializer will be used for that property. For example:
fastify.get('/foo', function (req, res) { req.log.info({req}) // log the serialized request object res.send('foo')})
Any user-supplied serializer will override the default serializer of the corresponding property.
### `loggerInstance`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#loggerinstance "Direct link to loggerinstance")
* Default: `null`
A custom logger instance. The logger must be a Pino instance or conform to the Pino interface by having the following methods: `info`, `error`, `debug`, `fatal`, `warn`, `trace`, `child`. For example:
const pino = require('pino')();const customLogger = { info: function (o, ...n) {}, warn: function (o, ...n) {}, error: function (o, ...n) {}, fatal: function (o, ...n) {}, trace: function (o, ...n) {}, debug: function (o, ...n) {}, child: function() { const child = Object.create(this); child.pino = pino.child(...arguments); return child; },};const fastify = require('fastify')({logger: customLogger});
### `disableRequestLogging`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#disablerequestlogging "Direct link to disablerequestlogging")
* Default: `false`
When logging is enabled, Fastify will issue an `info` level log message when a request is received and when the response for that request has been sent. By setting this option to `true`, these log messages will be disabled. This allows for more flexible request start and end logging by attaching custom `onRequest` and `onResponse` hooks.
The other log entries that will be disabled are:
* an error log written by the default `onResponse` hook on reply callback errors
* the error and info logs written by the `defaultErrorHandler` on error management
* the info log written by the `fourOhFour` handler when a non existent route is requested
Other log messages emitted by Fastify will stay enabled, like deprecation warnings and messages emitted when requests are received while the server is closing.
// Examples of hooks to replicate the disabled functionality.fastify.addHook('onRequest', (req, reply, done) => { req.log.info({ url: req.raw.url, id: req.id }, 'received request') done()})fastify.addHook('onResponse', (req, reply, done) => { req.log.info({ url: req.raw.originalUrl, statusCode: reply.raw.statusCode }, 'request completed') done()})
### `serverFactory`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#serverfactory "Direct link to serverfactory")
You can pass a custom HTTP server to Fastify by using the `serverFactory` option.
`serverFactory` is a function that takes a `handler` parameter, which takes the `request` and `response` objects as parameters, and an options object, which is the same you have passed to Fastify.
const serverFactory = (handler, opts) => { const server = http.createServer((req, res) => { handler(req, res) }) return server}const fastify = Fastify({ serverFactory })fastify.get('/', (req, reply) => { reply.send({ hello: 'world' })})fastify.listen({ port: 3000 })
Internally Fastify uses the API of Node core HTTP server, so if you are using a custom server you must be sure to have the same API exposed. If not, you can enhance the server instance inside the `serverFactory` function before the `return` statement.
### `caseSensitive`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#casesensitive "Direct link to casesensitive")
* Default: `true`
When `true` routes are registered as case-sensitive. That is, `/foo` is not equal to `/Foo`. When `false` then routes are case-insensitive.
Please note that setting this option to `false` goes against [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1)
.
By setting `caseSensitive` to `false`, all paths will be matched as lowercase, but the route parameters or wildcards will maintain their original letter casing. This option does not affect query strings, please refer to [`querystringParser`](https://fastify.dev/docs/v5.4.x/Reference/Server/#querystringparser)
to change their handling.
fastify.get('/user/:username', (request, reply) => { // Given the URL: /USER/NodeJS console.log(request.params.username) // -> 'NodeJS'})
### `allowUnsafeRegex`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowunsaferegex "Direct link to allowunsaferegex")
* Default `false`
Disabled by default, so routes only allow safe regular expressions. To use unsafe expressions, set `allowUnsafeRegex` to `true`.
fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => { // Throws an error without allowUnsafeRegex = true})
### `requestIdHeader`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidheader "Direct link to requestidheader")
* Default: `'request-id'`
The header name used to set the request-id. See [the request-id](https://fastify.dev/docs/v5.4.x/Reference/Logging/#logging-request-id)
section. Setting `requestIdHeader` to `true` will set the `requestIdHeader` to `"request-id"`. Setting `requestIdHeader` to a non-empty string will use the specified string as the `requestIdHeader`. By default `requestIdHeader` is set to `false` and will immediately use [genReqId](https://fastify.dev/docs/v5.4.x/Reference/Server/#genreqid)
. Setting `requestIdHeader` to an empty String (`""`) will set the requestIdHeader to `false`.
* Default: `false`
const fastify = require('fastify')({ requestIdHeader: 'x-custom-id', // -> use 'X-Custom-Id' header if available //requestIdHeader: false, // -> always use genReqId})
### `requestIdLogLabel`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidloglabel "Direct link to requestidloglabel")
* Default: `'reqId'`
Defines the label used for the request identifier when logging the request.
### `genReqId`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#genreqid "Direct link to genreqid")
* Default: `value of 'request-id' header if provided or monotonically increasing integers`
Function for generating the request-id. It will receive the _raw_ incoming request as a parameter. This function is expected to be error-free.
Especially in distributed systems, you may want to override the default ID generation behavior as shown below. For generating `UUID`s you may want to check out [hyperid](https://github.com/mcollina/hyperid)
.
> ℹ️ Note: `genReqId` will be not called if the header set in `[requestIdHeader](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidheader) ` is available (defaults to 'request-id').
let i = 0const fastify = require('fastify')({ genReqId: function (req) { return i++ }})
### `trustProxy`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#trustproxy "Direct link to trustproxy")
* Default: `false`
* `true/false`: Trust all proxies (`true`) or do not trust any proxies (`false`).
* `string`: Trust only given IP/CIDR (e.g. `'127.0.0.1'`). May be a list of comma separated values (e.g. `'127.0.0.1,192.168.1.1/24'`).
* `Array`: Trust only given IP/CIDR list (e.g. `['127.0.0.1']`).
* `number`: Trust the nth hop from the front-facing proxy server as the client.
* `Function`: Custom trust function that takes `address` as first argument
function myTrustFn(address, hop) { return address === '1.2.3.4' || hop === 1}
By enabling the `trustProxy` option, Fastify will know that it is sitting behind a proxy and that the `X-Forwarded-*` header fields may be trusted, which otherwise may be easily spoofed.
const fastify = Fastify({ trustProxy: true })
For more examples, refer to the [`@fastify/proxy-addr`](https://www.npmjs.com/package/@fastify/proxy-addr)
package.
You may access the `ip`, `ips`, `host` and `protocol` values on the [`request`](https://fastify.dev/docs/v5.4.x/Reference/Request/)
object.
fastify.get('/', (request, reply) => { console.log(request.ip) console.log(request.ips) console.log(request.host) console.log(request.protocol)})
> ℹ️ Note: If a request contains multiple `x-forwarded-host` or `x-forwarded-proto` headers, it is only the last one that is used to derive `request.hostname` and `request.protocol`.
### `pluginTimeout`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#plugintimeout "Direct link to plugintimeout")
* Default: `10000`
The maximum amount of time in _milliseconds_ in which a plugin can load. If not, [`ready`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ready)
will complete with an `Error` with code `'ERR_AVVIO_PLUGIN_TIMEOUT'`. When set to `0`, disables this check. This controls [avvio](https://www.npmjs.com/package/avvio)
's `timeout` parameter.
### `querystringParser`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#querystringparser "Direct link to querystringparser")
The default query string parser that Fastify uses is a more performant fork of Node.js's core `querystring` module called [`fast-querystring`](https://github.com/anonrig/fast-querystring)
.
You can use this option to use a custom parser, such as [`qs`](https://www.npmjs.com/package/qs)
.
If you only want the keys (and not the values) to be case insensitive we recommend using a custom parser to convert only the keys to lowercase.
const qs = require('qs')const fastify = require('fastify')({ querystringParser: str => qs.parse(str)})
You can also use Fastify's default parser but change some handling behavior, like the example below for case insensitive keys and values:
const querystring = require('fast-querystring')const fastify = require('fastify')({ querystringParser: str => querystring.parse(str.toLowerCase())})
### `exposeHeadRoutes`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#exposeheadroutes "Direct link to exposeheadroutes")
* Default: `true`
Automatically creates a sibling `HEAD` route for each `GET` route defined. If you want a custom `HEAD` handler without disabling this option, make sure to define it before the `GET` route.
### `constraints`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#constraints "Direct link to constraints")
Fastify's built-in route constraints are provided by `find-my-way`, which allows constraining routes by `version` or `host`. You can add new constraint strategies, or override the built-in strategies, by providing a `constraints` object with strategies for `find-my-way`. You can find more information on constraint strategies in the [find-my-way](https://github.com/delvedor/find-my-way)
documentation.
const customVersionStrategy = { storage: function () { const versions = {} return { get: (version) => { return versions[version] || null }, set: (version, store) => { versions[version] = store } } }, deriveVersion: (req, ctx) => { return req.headers['accept'] }}const fastify = require('fastify')({ constraints: { version: customVersionStrategy }})
### `return503OnClosing`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#return503onclosing "Direct link to return503onclosing")
* Default: `true`
Returns 503 after calling `close` server method. If `false`, the server routes the incoming request as usual.
### `ajv`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#ajv "Direct link to ajv")
Configure the Ajv v8 instance used by Fastify without providing a custom one. The default configuration is explained in the [#schema-validator](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schema-validator)
section.
const fastify = require('fastify')({ ajv: { customOptions: { removeAdditional: 'all' // Refer to [ajv options](https://ajv.js.org/options.html#removeadditional) }, plugins: [ require('ajv-merge-patch'), [require('ajv-keywords'), 'instanceof'] // Usage: [plugin, pluginOptions] - Plugin with options // Usage: plugin - Plugin without options ] }})
### `serializerOpts`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#serializeropts "Direct link to serializeropts")
Customize the options of the default [`fast-json-stringify`](https://github.com/fastify/fast-json-stringify#options)
instance that serializes the response's payload:
const fastify = require('fastify')({ serializerOpts: { rounding: 'ceil' }})
### `http2SessionTimeout`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2sessiontimeout "Direct link to http2sessiontimeout")
* Default: `72000`
Set a default [timeout](https://nodejs.org/api/http2.html#http2sessionsettimeoutmsecs-callback)
to every incoming HTTP/2 session in milliseconds. The session will be closed on the timeout.
This option is needed to offer a graceful "close" experience when using HTTP/2. The low default has been chosen to mitigate denial of service attacks. When the server is behind a load balancer or can scale automatically this value can be increased to fit the use case. Node core defaults this to `0`.
### `frameworkErrors`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#frameworkerrors "Direct link to frameworkerrors")
* Default: `null`
Fastify provides default error handlers for the most common use cases. It is possible to override one or more of those handlers with custom code using this option.
> ℹ️ Note: Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at present.
const fastify = require('fastify')({ frameworkErrors: function (error, req, res) { if (error instanceof FST_ERR_BAD_URL) { res.code(400) return res.send("Provided url is not valid") } else if(error instanceof FST_ERR_ASYNC_CONSTRAINT) { res.code(400) return res.send("Provided header is not valid") } else { res.send(err) } }})
### `clientErrorHandler`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#clienterrorhandler "Direct link to clienterrorhandler")
Set a [clientErrorHandler](https://nodejs.org/api/http.html#http_event_clienterror)
that listens to `error` events emitted by client connections and responds with a `400`.
It is possible to override the default `clientErrorHandler` using this option.
* Default:
function defaultClientErrorHandler (err, socket) { if (err.code === 'ECONNRESET') { return } const body = JSON.stringify({ error: http.STATUS_CODES['400'], message: 'Client Error', statusCode: 400 }) this.log.trace({ err }, 'client error') if (socket.writable) { socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) }}
> ℹ️ Note: `clientErrorHandler` operates with raw sockets. The handler is expected to return a properly formed HTTP response that includes a status line, HTTP headers and a message body. Before attempting to write the socket, the handler should check if the socket is still writable as it may have already been destroyed.
const fastify = require('fastify')({ clientErrorHandler: function (err, socket) { const body = JSON.stringify({ error: { message: 'Client error', code: '400' } }) // `this` is bound to fastify instance this.log.trace({ err }, 'client error') // the handler is responsible for generating a valid HTTP response socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) }})
### `rewriteUrl`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#rewriteurl "Direct link to rewriteurl")
Set a sync callback function that must return a string that allows rewriting URLs. This is useful when you are behind a proxy that changes the URL. Rewriting a URL will modify the `url` property of the `req` object.
Note that `rewriteUrl` is called _before_ routing, it is not encapsulated and it is an instance-wide configuration.
// @param {object} req The raw Node.js HTTP request, not the `FastifyRequest` object.// @this Fastify The root Fastify instance (not an encapsulated instance).// @returns {string} The path that the request should be mapped to.function rewriteUrl (req) { if (req.url === '/hi') { this.log.debug({ originalUrl: req.url, url: '/hello' }, 'rewrite url'); return '/hello' } else { return req.url; }}
### `useSemicolonDelimiter`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#usesemicolondelimiter "Direct link to usesemicolondelimiter")
* Default `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
which supports, separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`. This decision originated from \[delvedor/find-my-way#76\] ([https://github.com/delvedor/find-my-way/issues/76](https://github.com/delvedor/find-my-way/issues/76)
). Thus, this option will support backwards compatiblilty for the need to split on `;`. To enable support for splitting on `;` set `useSemicolonDelimiter` to `true`.
const fastify = require('fastify')({ useSemicolonDelimiter: true})fastify.get('/dev', async (request, reply) => { // An example request such as `/dev;foo=bar` // Will produce the following query params result `{ foo = 'bar' }` return request.query})
### `allowErrorHandlerOverride`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowerrorhandleroverride "Direct link to allowerrorhandleroverride")
* **Default:** `true`
> ⚠ **Warning:** This option will be set to `false` by default in the next major release.
When set to `false`, it prevents `setErrorHandler` from being called multiple times within the same scope, ensuring that the previous error handler is not unintentionally overridden.
#### Example of incorrect usage:[](https://fastify.dev/docs/v5.4.x/Reference/Server/#example-of-incorrect-usage "Direct link to Example of incorrect usage:")
app.setErrorHandler(function freeSomeResources () { // Never executed, memory leaks})app.setErrorHandler(function anotherErrorHandler () { // Overrides the previous handler})
Instance[](https://fastify.dev/docs/v5.4.x/Reference/Server/#instance "Direct link to Instance")
--------------------------------------------------------------------------------------------------
### Server Methods[](https://fastify.dev/docs/v5.4.x/Reference/Server/#server-methods "Direct link to Server Methods")
#### server[](https://fastify.dev/docs/v5.4.x/Reference/Server/#server "Direct link to server")
`fastify.server`: The Node core [server](https://nodejs.org/api/http.html#http_class_http_server)
object as returned by the [**`Fastify factory function`**](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory)
.
> ⚠ Warning: If utilized improperly, certain Fastify features could be disrupted. It is recommended to only use it for attaching listeners.
#### after[](https://fastify.dev/docs/v5.4.x/Reference/Server/#after "Direct link to after")
Invoked when the current plugin and all the plugins that have been registered within it have finished loading. It is always executed before the method `fastify.ready`.
fastify .register((instance, opts, done) => { console.log('Current plugin') done() }) .after(err => { console.log('After current plugin') }) .register((instance, opts, done) => { console.log('Next plugin') done() }) .ready(err => { console.log('Everything has been loaded') })
In case `after()` is called without a function, it returns a `Promise`:
fastify.register(async (instance, opts) => { console.log('Current plugin')})await fastify.after()console.log('After current plugin')fastify.register(async (instance, opts) => { console.log('Next plugin')})await fastify.ready()console.log('Everything has been loaded')
#### ready[](https://fastify.dev/docs/v5.4.x/Reference/Server/#ready "Direct link to ready")
Function called when all the plugins have been loaded. It takes an error parameter if something went wrong.
fastify.ready(err => { if (err) throw err})
If it is called without any arguments, it will return a `Promise`:
fastify.ready().then(() => { console.log('successfully booted!')}, (err) => { console.log('an error happened', err)})
#### listen[](https://fastify.dev/docs/v5.4.x/Reference/Server/#listen "Direct link to listen")
Starts the server and internally waits for the `.ready()` event. The signature is `.listen([options][, callback])`. Both the `options` object and the `callback` parameters extend the [Node.js core](https://nodejs.org/api/net.html#serverlistenoptions-callback)
options object. Thus, all core options are available with the following additional Fastify specific options:
### `listenTextResolver`[](https://fastify.dev/docs/v5.4.x/Reference/Server/#listentextresolver "Direct link to listentextresolver")
Set an optional resolver for the text to log after server has been successfully started. It is possible to override the default `Server listening at [address]` log entry using this option.
server.listen({ port: 9080, listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }})
By default, the server will listen on the address(es) resolved by `localhost` when no specific host is provided. If listening on any available interface is desired, then specifying `0.0.0.0` for the address will listen on all IPv4 addresses. The address argument provided above will then return the first such IPv4 address. The following table details the possible values for `host` when targeting `localhost`, and what the result of those values for `host` will be.
| Host | IPv4 | IPv6 |
| --- | --- | --- |
| `::` | ✅\* | ✅ |
| `::` + [`ipv6Only`](https://nodejs.org/api/net.html#serverlistenoptions-callback) | 🚫 | ✅ |
| `0.0.0.0` | ✅ | 🚫 |
| `localhost` | ✅ | ✅ |
| `127.0.0.1` | ✅ | 🚫 |
| `::1` | 🚫 | ✅ |
\* Using `::` for the address will listen on all IPv6 addresses and, depending on OS, may also listen on [all IPv4 addresses](https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback)
.
Be careful when deciding to listen on all interfaces; it comes with inherent [security risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/)
.
The default is to listen on `port: 0` (which picks the first available open port) and `host: 'localhost'`:
fastify.listen((err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
Specifying an address is also supported:
fastify.listen({ port: 3000, host: '127.0.0.1' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
If no callback is provided a Promise is returned:
fastify.listen({ port: 3000 }) .then((address) => console.log(`server listening on ${address}`)) .catch(err => { console.log('Error starting server:', err) process.exit(1) })
When deploying to a Docker, and potentially other, containers, it is advisable to listen on `0.0.0.0` because they do not default to exposing mapped ports to `localhost`:
fastify.listen({ port: 3000, host: '0.0.0.0' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
If the `port` is omitted (or is set to zero), a random available port is automatically chosen (available via `fastify.server.address().port`).
The default options of listen are:
fastify.listen({ port: 0, host: 'localhost', exclusive: false, readableAll: false, writableAll: false, ipv6Only: false}, (err) => {})
#### addresses[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addresses "Direct link to addresses")
This method returns an array of addresses that the server is listening on. If you call it before `listen()` is called or after the `close()` function, it will return an empty array.
await fastify.listen({ port: 8080 })const addresses = fastify.addresses()// [// { port: 8080, family: 'IPv6', address: '::1' },// { port: 8080, family: 'IPv4', address: '127.0.0.1' }// ]
Note that the array contains the `fastify.server.address()` too.
#### routing[](https://fastify.dev/docs/v5.4.x/Reference/Server/#routing "Direct link to routing")
Method to access the `lookup` method of the internal router and match the request to the appropriate handler:
fastify.routing(req, res)
#### route[](https://fastify.dev/docs/v5.4.x/Reference/Server/#route "Direct link to route")
Method to add routes to the server, it also has shorthand functions, check [here](https://fastify.dev/docs/v5.4.x/Reference/Routes/)
.
#### hasRoute[](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasroute "Direct link to hasRoute")
Method to check if a route is already registered to the internal router. It expects an object as the payload. `url` and `method` are mandatory fields. It is possible to also specify `constraints`. The method returns `true` if the route is registered or `false` if not.
const routeExists = fastify.hasRoute({ url: '/', method: 'GET', constraints: { version: '1.0.0' } // optional})if (routeExists === false) { // add route}
#### findRoute[](https://fastify.dev/docs/v5.4.x/Reference/Server/#findroute "Direct link to findRoute")
Method to retrieve a route already registered to the internal router. It expects an object as the payload. `url` and `method` are mandatory fields. It is possible to also specify `constraints`. The method returns a route object or `null` if the route cannot be found.
const route = fastify.findRoute({ url: '/artists/:artistId', method: 'GET', constraints: { version: '1.0.0' } // optional})if (route !== null) { // perform some route checks console.log(route.params) // `{artistId: ':artistId'}`}
#### close[](https://fastify.dev/docs/v5.4.x/Reference/Server/#close "Direct link to close")
`fastify.close(callback)`: call this function to close the server instance and run the [`'onClose'`](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#on-close)
hook.
Calling `close` will also cause the server to respond to every new incoming request with a `503` error and destroy that request. See [`return503OnClosing` flags](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory-return-503-on-closing)
for changing this behavior.
If it is called without any arguments, it will return a Promise:
fastify.close().then(() => { console.log('successfully closed!')}, (err) => { console.log('an error happened', err)})
#### decorate\*[](https://fastify.dev/docs/v5.4.x/Reference/Server/#decorate "Direct link to decorate*")
Function useful if you need to decorate the fastify instance, Reply or Request, check [here](https://fastify.dev/docs/v5.4.x/Reference/Decorators/)
.
#### register[](https://fastify.dev/docs/v5.4.x/Reference/Server/#register "Direct link to register")
Fastify allows the user to extend its functionality with plugins. A plugin can be a set of routes, a server decorator, or whatever, check [here](https://fastify.dev/docs/v5.4.x/Reference/Plugins/)
.
#### addHook[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addhook "Direct link to addHook")
Function to add a specific hook in the lifecycle of Fastify, check [here](https://fastify.dev/docs/v5.4.x/Reference/Hooks/)
.
#### prefix[](https://fastify.dev/docs/v5.4.x/Reference/Server/#prefix "Direct link to prefix")
The full path that will be prefixed to a route.
Example:
fastify.register(function (instance, opts, done) { instance.get('/foo', function (request, reply) { // Will log "prefix: /v1" request.log.info('prefix: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) instance.register(function (instance, opts, done) { instance.get('/bar', function (request, reply) { // Will log "prefix: /v1/v2" request.log.info('prefix: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) done() }, { prefix: '/v2' }) done()}, { prefix: '/v1' })
#### pluginName[](https://fastify.dev/docs/v5.4.x/Reference/Server/#pluginname "Direct link to pluginName")
Name of the current plugin. The root plugin is called `'fastify'`. There are different ways to define a name (in order).
1. If you use [fastify-plugin](https://github.com/fastify/fastify-plugin)
the metadata `name` is used.
2. If the exported plugin has the `Symbol.for('fastify.display-name')` property, then the value of that property is used. Example: `pluginFn[Symbol.for('fastify.display-name')] = "Custom Name"`
3. If you `module.exports` a plugin the filename is used.
4. If you use a regular [function declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Defining_functions)
the function name is used.
_Fallback_: The first two lines of your plugin will represent the plugin name. Newlines are replaced by `--`. This will help to identify the root cause when you deal with many plugins.
> ⚠ Warning: If you have to deal with nested plugins, the name differs with the usage of the [fastify-plugin](https://github.com/fastify/fastify-plugin)
> because no new scope is created and therefore we have no place to attach contextual data. In that case, the plugin name will represent the boot order of all involved plugins in the format of `fastify -> plugin-A -> plugin-B`.
#### hasPlugin[](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasplugin "Direct link to hasPlugin")
Method to check if a specific plugin has been registered. Relies on the plugin metadata name. Returns `true` if the plugin is registered. Otherwise, returns `false`.
const fastify = require('fastify')()fastify.register(require('@fastify/cookie'), { secret: 'my-secret', parseOptions: {}})fastify.ready(() => { fastify.hasPlugin('@fastify/cookie') // true})
### listeningOrigin[](https://fastify.dev/docs/v5.4.x/Reference/Server/#listeningorigin "Direct link to listeningOrigin")
The current origin the server is listening to. For example, a TCP socket based server returns a base address like `http://127.0.0.1:3000`, and a Unix socket server will return the socket path, e.g. `fastify.temp.sock`.
#### log[](https://fastify.dev/docs/v5.4.x/Reference/Server/#log "Direct link to log")
The logger instance, check [here](https://fastify.dev/docs/v5.4.x/Reference/Logging/)
.
#### version[](https://fastify.dev/docs/v5.4.x/Reference/Server/#version "Direct link to version")
Fastify version of the instance. Used for plugin support. See [Plugins](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#handle-the-scope)
for information on how the version is used by plugins.
#### inject[](https://fastify.dev/docs/v5.4.x/Reference/Server/#inject "Direct link to inject")
Fake HTTP injection (for testing purposes) [here](https://fastify.dev/docs/v5.4.x/Guides/Testing/#benefits-of-using-fastifyinject)
.
#### addHttpMethod[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addhttpmethod "Direct link to addHttpMethod")
Fastify supports the `GET`, `HEAD`, `TRACE`, `DELETE`, `OPTIONS`, `PATCH`, `PUT` and `POST` HTTP methods by default. The `addHttpMethod` method allows to add any non standard HTTP methods to the server that are [supported by Node.js](https://nodejs.org/api/http.html#httpmethods)
.
// Add a new HTTP method called 'MKCOL' that supports a request bodyfastify.addHttpMethod('MKCOL', { hasBody: true, })// Add a new HTTP method called 'COPY' that does not support a request bodyfastify.addHttpMethod('COPY')
After calling `addHttpMethod`, it is possible to use the route shorthand methods to define routes for the new HTTP method:
fastify.addHttpMethod('MKCOL', { hasBody: true })fastify.mkcol('/', (req, reply) => { // Handle the 'MKCOL' request})
#### addSchema[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addschema "Direct link to addSchema")
`fastify.addSchema(schemaObj)`, adds a JSON schema to the Fastify instance. This allows you to reuse it everywhere in your application just by using the standard `$ref` keyword.
To learn more, read the [Validation and Serialization](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/)
documentation.
#### getSchemas[](https://fastify.dev/docs/v5.4.x/Reference/Server/#getschemas "Direct link to getSchemas")
`fastify.getSchemas()`, returns a hash of all schemas added via `.addSchema`. The keys of the hash are the `$id`s of the JSON Schema provided.
#### getSchema[](https://fastify.dev/docs/v5.4.x/Reference/Server/#getschema "Direct link to getSchema")
`fastify.getSchema(id)`, return the JSON schema added with `.addSchema` and the matching `id`. It returns `undefined` if it is not found.
#### setReplySerializer[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setreplyserializer "Direct link to setReplySerializer")
Set the reply serializer for all the routes. This will be used as default if a [Reply.serializer(func)](https://fastify.dev/docs/v5.4.x/Reference/Reply/#serializerfunc)
has not been set. The handler is fully encapsulated, so different plugins can set different error handlers. Note: the function parameter is called only for status `2xx`. Check out the [`setErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler)
for errors.
fastify.setReplySerializer(function (payload, statusCode){ // serialize the payload with a sync function return `my serialized ${statusCode} content: ${payload}`})
#### setValidatorCompiler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setvalidatorcompiler "Direct link to setValidatorCompiler")
Set the schema validator compiler for all routes. See [#schema-validator](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schema-validator)
.
#### setSchemaErrorFormatter[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setschemaerrorformatter "Direct link to setSchemaErrorFormatter")
Set the schema error formatter for all routes. See [#error-handling](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schemaerrorformatter)
.
#### setSerializerCompiler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setserializercompiler "Direct link to setSerializerCompiler")
Set the schema serializer compiler for all routes. See [#schema-serializer](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schema-serializer)
.
> ℹ️ Note: [`setReplySerializer`](https://fastify.dev/docs/v5.4.x/Reference/Server/#set-reply-serializer)
> has priority if set!
#### validatorCompiler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#validatorcompiler "Direct link to validatorCompiler")
This property can be used to get the schema validator. If not set, it will be `null` until the server starts, then it will be a function with the signature `function ({ schema, method, url, httpPart })` that returns the input `schema` compiled to a function for validating data. The input `schema` can access all the shared schemas added with [`.addSchema`](https://fastify.dev/docs/v5.4.x/Reference/Server/#add-schema)
function.
#### serializerCompiler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#serializercompiler "Direct link to serializerCompiler")
This property can be used to get the schema serializer. If not set, it will be `null` until the server starts, then it will be a function with the signature `function ({ schema, method, url, httpPart })` that returns the input `schema` compiled to a function for validating data. The input `schema` can access all the shared schemas added with [`.addSchema`](https://fastify.dev/docs/v5.4.x/Reference/Server/#add-schema)
function.
#### schemaErrorFormatter[](https://fastify.dev/docs/v5.4.x/Reference/Server/#schemaerrorformatter "Direct link to schemaErrorFormatter")
This property can be used to set a function to format errors that happen while the `validationCompiler` fails to validate the schema. See [#error-handling](https://fastify.dev/docs/v5.4.x/Reference/Validation-and-Serialization/#schemaerrorformatter)
.
#### schemaController[](https://fastify.dev/docs/v5.4.x/Reference/Server/#schemacontroller "Direct link to schemaController")
This property can be used to fully manage:
* `bucket`: where the schemas of your application will be stored
* `compilersFactory`: what module must compile the JSON schemas
It can be useful when your schemas are stored in another data structure that is unknown to Fastify.
Another use case is to tweak all the schemas processing. Doing so it is possible to use Ajv v8 JTD or Standalone feature. To use such as JTD or the Standalone mode, refers to the [`@fastify/ajv-compiler` documentation](https://github.com/fastify/ajv-compiler#usage)
.
const fastify = Fastify({ schemaController: { /** * This factory is called whenever `fastify.register()` is called. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} parentSchemas these schemas will be returned by the * `getSchemas()` method function of the returned `bucket`. */ bucket: function factory (parentSchemas) { return { add (inputSchema) { // This function must store the schema added by the user. // This function is invoked when `fastify.addSchema()` is called. }, getSchema (schema$id) { // This function must return the raw schema requested by the `schema$id`. // This function is invoked when `fastify.getSchema(id)` is called. return aSchema }, getSchemas () { // This function must return all the schemas referenced by the routes schemas' $ref // It must return a JSON where the property is the schema `$id` and the value is the raw JSON Schema. const allTheSchemaStored = { 'schema$id1': schema1, 'schema$id2': schema2 } return allTheSchemaStored } } }, /** * The compilers factory lets you fully control the validator and serializer * in the Fastify's lifecycle, providing the encapsulation to your compilers. */ compilersFactory: { /** * This factory is called whenever a new validator instance is needed. * It may be called whenever `fastify.register()` is called only if new schemas have been added to the * encapsulation context. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} externalSchemas these schemas will be returned by the * `bucket.getSchemas()`. Needed to resolve the external references $ref. * @param {object} ajvServerOption the server `ajv` options to build your compilers accordingly */ buildValidator: function factory (externalSchemas, ajvServerOption) { // This factory function must return a schema validator compiler. // See [#schema-validator](./Validation-and-Serialization.md#schema-validator) for details. const yourAjvInstance = new Ajv(ajvServerOption.customOptions) return function validatorCompiler ({ schema, method, url, httpPart }) { return yourAjvInstance.compile(schema) } }, /** * This factory is called whenever a new serializer instance is needed. * It may be called whenever `fastify.register()` is called only if new schemas have been added to the * encapsulation context. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} externalSchemas these schemas will be returned by the * `bucket.getSchemas()`. Needed to resolve the external references $ref. * @param {object} serializerOptsServerOption the server `serializerOpts` * options to build your compilers accordingly */ buildSerializer: function factory (externalSchemas, serializerOptsServerOption) { // This factory function must return a schema serializer compiler. // See [#schema-serializer](./Validation-and-Serialization.md#schema-serializer) for details. return function serializerCompiler ({ schema, method, url, httpStatus, contentType }) { return data => JSON.stringify(data) } } } }});
#### setNotFoundHandler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setnotfoundhandler "Direct link to setNotFoundHandler")
`fastify.setNotFoundHandler(handler(request, reply))`: set the 404 handler. This call is encapsulated by prefix, so different plugins can set different not found handlers if a different [`prefix` option](https://fastify.dev/docs/v5.4.x/Reference/Plugins/#route-prefixing-option)
is passed to `fastify.register()`. The handler is treated as a regular route handler so requests will go through the full [Fastify lifecycle](https://fastify.dev/docs/v5.4.x/Reference/Lifecycle/#lifecycle)
. _async-await_ is supported as well.
You can also register [`preValidation`](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-hooks)
and [`preHandler`](https://fastify.dev/docs/v5.4.x/Reference/Hooks/#route-hooks)
hooks for the 404 handler.
> ℹ️ Note: The `preValidation` hook registered using this method will run for a route that Fastify does not recognize and **not** when a route handler manually calls [`reply.callNotFound`](https://fastify.dev/docs/v5.4.x/Reference/Reply/#call-not-found)
> . In which case, only preHandler will be run.
fastify.setNotFoundHandler({ preValidation: (req, reply, done) => { // your code done() }, preHandler: (req, reply, done) => { // your code done() }}, function (request, reply) { // Default not found handler with preValidation and preHandler hooks})fastify.register(function (instance, options, done) { instance.setNotFoundHandler(function (request, reply) { // Handle not found request without preValidation and preHandler hooks // to URLs that begin with '/v1' }) done()}, { prefix: '/v1' })
Fastify calls setNotFoundHandler to add a default 404 handler at startup before plugins are registered. If you would like to augment the behavior of the default 404 handler, for example with plugins, you can call setNotFoundHandler with no arguments `fastify.setNotFoundHandler()` within the context of these registered plugins.
> ℹ️ Note: Some config properties from the request object will be undefined inside the custom not found handler. E.g.: `request.routeOptions.url`, `routeOptions.method` and `routeOptions.config`. This method design goal is to allow calling the common not found route. To return a per-route customized 404 response, you can do it in the response itself.
#### setErrorHandler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#seterrorhandler "Direct link to setErrorHandler")
`fastify.setErrorHandler(handler(error, request, reply))`: Set a function that will be called whenever an error happens. The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set different error handlers. _async-await_ is supported as well.
If the error `statusCode` is less than 400, Fastify will automatically set it to 500 before calling the error handler.
`setErrorHandler` will _**not**_ catch:
* errors thrown in an `onResponse` hook because the response has already been sent to the client. Use the `onSend` hook instead.
* not found (404) errors. Use [`setNotFoundHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#set-not-found-handler)
instead.
fastify.setErrorHandler(function (error, request, reply) { // Log error this.log.error(error) // Send error response reply.status(409).send({ ok: false })})
Fastify is provided with a default function that is called if no error handler is set. It can be accessed using `fastify.errorHandler` and it logs the error with respect to its `statusCode`.
const statusCode = error.statusCodeif (statusCode >= 500) { log.error(error)} else if (statusCode >= 400) { log.info(error)} else { log.error(error)}
> ⚠ Warning: Avoid calling setErrorHandler multiple times in the same scope. See [`allowErrorHandlerOverride`](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowerrorhandleroverride)
> .
#### setChildLoggerFactory[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setchildloggerfactory "Direct link to setChildLoggerFactory")
`fastify.setChildLoggerFactory(factory(logger, bindings, opts, rawReq))`: Set a function that will be called when creating a child logger instance for each request which allows for modifying or adding child logger bindings and logger options, or returning a custom child logger implementation.
Child logger bindings have a performance advantage over per-log bindings because they are pre-serialized by Pino when the child logger is created.
The first parameter is the parent logger instance, followed by the default bindings and logger options which should be passed to the child logger, and finally the raw request (not a Fastify request object). The function is bound with `this` being the Fastify instance.
For example:
const fastify = require('fastify')({ childLoggerFactory: function (logger, bindings, opts, rawReq) { // Calculate additional bindings from the request if needed bindings.traceContext = rawReq.headers['x-cloud-trace-context'] return logger.child(bindings, opts) }})
The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set different logger factories.
#### setGenReqId[](https://fastify.dev/docs/v5.4.x/Reference/Server/#setgenreqid "Direct link to setGenReqId")
`fastify.setGenReqId(function (rawReq))` Synchronous function for setting the request-id for additional Fastify instances. It will receive the _raw_ incoming request as a parameter. The provided function should not throw an Error in any case.
Especially in distributed systems, you may want to override the default ID generation behavior to handle custom ways of generating different IDs in order to handle different use cases. Such as observability or webhooks plugins.
For example:
const fastify = require('fastify')({ genReqId: (req) => { return 'base' }})fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // custom request ID for `/webhooks` return 'webhooks-id' }) done()}, { prefix: '/webhooks' })fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // custom request ID for `/observability` return 'observability-id' }) done()}, { prefix: '/observability' })
The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set a different request ID.
#### addConstraintStrategy[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addconstraintstrategy "Direct link to addConstraintStrategy")
Function to add a custom constraint strategy. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request.
Add a custom constraint strategy using the `fastify.addConstraintStrategy` method:
const customResponseTypeStrategy = { // strategy name for referencing in the route handler `constraints` options name: 'accept', // storage factory for storing routes in the find-my-way route tree storage: function () { let handlers = {} return { get: (type) => { return handlers[type] || null }, set: (type, store) => { handlers[type] = store } } }, // function to get the value of the constraint from each incoming request deriveConstraint: (req, ctx) => { return req.headers['accept'] }, // optional flag marking if handlers without constraints can match requests that have a value for this constraint mustMatchWhenDerived: true}const router = Fastify();router.addConstraintStrategy(customResponseTypeStrategy);
#### hasConstraintStrategy[](https://fastify.dev/docs/v5.4.x/Reference/Server/#hasconstraintstrategy "Direct link to hasConstraintStrategy")
The `fastify.hasConstraintStrategy(strategyName)` checks if there already exists a custom constraint strategy with the same name.
#### printRoutes[](https://fastify.dev/docs/v5.4.x/Reference/Server/#printroutes "Direct link to printRoutes")
`fastify.printRoutes()`: Fastify router builds a tree of routes for each HTTP method. If you call the prettyPrint without specifying an HTTP method, it will merge all the trees into one and print it. The merged tree doesn't represent the internal router structure. **Do not use it for debugging.**
_Remember to call it inside or after a `ready` call._
fastify.get('/test', () => {})fastify.get('/test/hello', () => {})fastify.get('/testing', () => {})fastify.get('/testing/:param', () => {})fastify.put('/update', () => {})fastify.ready(() => { console.log(fastify.printRoutes()) // └── / // ├── test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── / // │ └── :param (GET) // └── update (PUT)})
If you want to print the internal router tree, you should specify the `method` param. Printed tree will represent the internal router structure. **You can use it for debugging.**
console.log(fastify.printRoutes({ method: 'GET' })) // └── / // └── test (GET) // ├── /hello (GET) // └── ing (GET) // └── / // └── :param (GET) console.log(fastify.printRoutes({ method: 'PUT' })) // └── / // └── update (PUT)
`fastify.printRoutes({ commonPrefix: false })` will print compressed trees. This may be useful when you have a large number of routes with common prefixes. It doesn't represent the internal router structure. **Do not use it for debugging.**
console.log(fastify.printRoutes({ commonPrefix: false })) // ├── /test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── /:param (GET) // └── /update (PUT)
`fastify.printRoutes({ includeMeta: (true | []) })` will display properties from the `route.store` object for each displayed route. This can be an `array` of keys (e.g. `['onRequest', Symbol('key')]`), or `true` to display all properties. A shorthand option, `fastify.printRoutes({ includeHooks: true })` will include all [hooks](https://fastify.dev/docs/v5.4.x/Reference/Hooks/)
.
fastify.get('/test', () => {}) fastify.get('/test/hello', () => {}) const onTimeout = () => {} fastify.addHook('onRequest', () => {}) fastify.addHook('onTimeout', onTimeout) console.log(fastify.printRoutes({ includeHooks: true, includeMeta: ['errorHandler'] })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()" // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()" console.log(fastify.printRoutes({ includeHooks: true })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"]
#### printPlugins[](https://fastify.dev/docs/v5.4.x/Reference/Server/#printplugins "Direct link to printPlugins")
`fastify.printPlugins()`: Prints the representation of the internal plugin tree used by the avvio, useful for debugging require order issues.
_Remember to call it inside or after a `ready` call._
fastify.register(async function foo (instance) { instance.register(async function bar () {})})fastify.register(async function baz () {})fastify.ready(() => { console.error(fastify.printPlugins()) // will output the following to stderr: // └── root // ├── foo // │ └── bar // └── baz})
#### addContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/Server/#addcontenttypeparser "Direct link to addContentTypeParser")
`fastify.addContentTypeParser(content-type, options, parser)` is used to pass a custom parser for a given content type. Useful for adding parsers for custom content types, e.g. `text/json, application/vnd.oasis.opendocument.text`. `content-type` can be a string, string array or RegExp.
// The two arguments passed to getDefaultJsonParser are for ProtoType poisoning// and Constructor Poisoning configuration respectively. The possible values are// 'ignore', 'remove', 'error'. ignore skips all validations and it is similar// to calling JSON.parse() directly. See the// [`secure-json-parse` documentation](https://github.com/fastify/secure-json-parse#api) for more information.fastify.addContentTypeParser('text/json', { asString: true }, fastify.getDefaultJsonParser('ignore', 'ignore'))
#### hasContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/Server/#hascontenttypeparser "Direct link to hasContentTypeParser")
`fastify.hasContentTypeParser(contentType)` is used to check whether there is a content type parser in the current context for the specified content type.
fastify.hasContentTypeParser('text/json')fastify.hasContentTypeParser(/^.+\/json$/)
#### removeContentTypeParser[](https://fastify.dev/docs/v5.4.x/Reference/Server/#removecontenttypeparser "Direct link to removeContentTypeParser")
`fastify.removeContentTypeParser(contentType)` is used to remove content type parsers in the current context. This method allows for example to remove the both built-in parsers for `application/json` and `text/plain`.
fastify.removeContentTypeParser('application/json')fastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.4.x/Reference/Server/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
The `fastify.removeAllContentTypeParsers()` method allows all content type parsers in the current context to be removed. A use case of this method is the implementation of catch-all content type parser. Before adding this parser with `fastify.addContentTypeParser()` one could call the `removeAllContentTypeParsers` method.
For more details about the usage of the different content type parser APIs see [here](https://fastify.dev/docs/v5.4.x/Reference/ContentTypeParser/#usage)
.
#### getDefaultJsonParser[](https://fastify.dev/docs/v5.4.x/Reference/Server/#getdefaultjsonparser "Direct link to getDefaultJsonParser")
`fastify.getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning)` takes two arguments. First argument is ProtoType poisoning configuration and second argument is constructor poisoning configuration. See the [`secure-json-parse` documentation](https://github.com/fastify/secure-json-parse#api)
for more information.
#### defaultTextParser[](https://fastify.dev/docs/v5.4.x/Reference/Server/#defaulttextparser "Direct link to defaultTextParser")
`fastify.defaultTextParser()` can be used to parse content as plain text.
fastify.addContentTypeParser('text/json', { asString: true }, fastify.defaultTextParser)
#### errorHandler[](https://fastify.dev/docs/v5.4.x/Reference/Server/#errorhandler "Direct link to errorHandler")
`fastify.errorHandler` can be used to handle errors using fastify's default error handler.
fastify.get('/', { errorHandler: (error, request, reply) => { if (error.code === 'SOMETHING_SPECIFIC') { reply.send({ custom: 'response' }) return } fastify.errorHandler(error, request, response) }}, handler)
#### childLoggerFactory[](https://fastify.dev/docs/v5.4.x/Reference/Server/#childloggerfactory "Direct link to childLoggerFactory")
`fastify.childLoggerFactory` returns the custom logger factory function for the Fastify instance. See the [`childLoggerFactory` config option](https://fastify.dev/docs/v5.4.x/Reference/Server/#setchildloggerfactory)
for more info.
#### Symbol.asyncDispose[](https://fastify.dev/docs/v5.4.x/Reference/Server/#symbolasyncdispose "Direct link to Symbol.asyncDispose")
`fastify[Symbol.asyncDispose]` is a symbol that can be used to define an asynchronous function that will be called when the Fastify instance is closed.
It's commonly used alongside the `using` TypeScript keyword to ensure that resources are cleaned up when the Fastify instance is closed.
This combines perfectly inside short lived processes or unit tests, where you must close all Fastify resources after returning from inside the function.
test('Uses app and closes it afterwards', async () => { await using app = fastify(); // do something with app.})
In the above example, Fastify is closed automatically after the test finishes.
Read more about the [ECMAScript Explicit Resource Management](https://tc39.es/proposal-explicit-resource-management)
and the [using keyword](https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/)
introduced in TypeScript 5.2.
#### initialConfig[](https://fastify.dev/docs/v5.4.x/Reference/Server/#initialconfig "Direct link to initialConfig")
`fastify.initialConfig`: Exposes a frozen read-only object registering the initial options passed down by the user to the Fastify instance.
The properties that can currently be exposed are:
* connectionTimeout
* keepAliveTimeout
* bodyLimit
* caseSensitive
* allowUnsafeRegex
* http2
* https (it will return `false`/`true` or `{ allowHTTP1: true/false }` if explicitly passed)
* ignoreTrailingSlash
* disableRequestLogging
* maxParamLength
* onProtoPoisoning
* onConstructorPoisoning
* pluginTimeout
* requestIdHeader
* requestIdLogLabel
* http2SessionTimeout
* useSemicolonDelimiter
const { readFileSync } = require('node:fs')const Fastify = require('fastify')const fastify = Fastify({ https: { allowHTTP1: true, key: readFileSync('./fastify.key'), cert: readFileSync('./fastify.cert') }, logger: { level: 'trace'}, ignoreTrailingSlash: true, maxParamLength: 200, caseSensitive: true, trustProxy: '127.0.0.1,192.168.1.1/24',})console.log(fastify.initialConfig)/*will log :{ caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200}*/fastify.register(async (instance, opts) => { instance.get('/', async (request, reply) => { return instance.initialConfig /* will return : { caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200 } */ }) instance.get('/error', async (request, reply) => { // will throw an error because initialConfig is read-only // and can not be modified instance.initialConfig.https.allowHTTP1 = false return instance.initialConfig })})// Start listening.fastify.listen({ port: 3000 }, (err) => { if (err) { fastify.log.error(err) process.exit(1) }})
* [Factory](https://fastify.dev/docs/v5.4.x/Reference/Server/#factory)
* [`http`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http)
* [`http2`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2)
* [`https`](https://fastify.dev/docs/v5.4.x/Reference/Server/#https)
* [`connectionTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#connectiontimeout)
* [`keepAliveTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#keepalivetimeout)
* [`forceCloseConnections`](https://fastify.dev/docs/v5.4.x/Reference/Server/#forcecloseconnections)
* [`maxRequestsPerSocket`](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxrequestspersocket)
* [`requestTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requesttimeout)
* [`ignoreTrailingSlash`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoretrailingslash)
* [`ignoreDuplicateSlashes`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ignoreduplicateslashes)
* [`maxParamLength`](https://fastify.dev/docs/v5.4.x/Reference/Server/#maxparamlength)
* [`bodyLimit`](https://fastify.dev/docs/v5.4.x/Reference/Server/#bodylimit)
* [`onProtoPoisoning`](https://fastify.dev/docs/v5.4.x/Reference/Server/#onprotopoisoning)
* [`onConstructorPoisoning`](https://fastify.dev/docs/v5.4.x/Reference/Server/#onconstructorpoisoning)
* [`logger`](https://fastify.dev/docs/v5.4.x/Reference/Server/#logger)
* [`loggerInstance`](https://fastify.dev/docs/v5.4.x/Reference/Server/#loggerinstance)
* [`disableRequestLogging`](https://fastify.dev/docs/v5.4.x/Reference/Server/#disablerequestlogging)
* [`serverFactory`](https://fastify.dev/docs/v5.4.x/Reference/Server/#serverfactory)
* [`caseSensitive`](https://fastify.dev/docs/v5.4.x/Reference/Server/#casesensitive)
* [`allowUnsafeRegex`](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowunsaferegex)
* [`requestIdHeader`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidheader)
* [`requestIdLogLabel`](https://fastify.dev/docs/v5.4.x/Reference/Server/#requestidloglabel)
* [`genReqId`](https://fastify.dev/docs/v5.4.x/Reference/Server/#genreqid)
* [`trustProxy`](https://fastify.dev/docs/v5.4.x/Reference/Server/#trustproxy)
* [`pluginTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#plugintimeout)
* [`querystringParser`](https://fastify.dev/docs/v5.4.x/Reference/Server/#querystringparser)
* [`exposeHeadRoutes`](https://fastify.dev/docs/v5.4.x/Reference/Server/#exposeheadroutes)
* [`constraints`](https://fastify.dev/docs/v5.4.x/Reference/Server/#constraints)
* [`return503OnClosing`](https://fastify.dev/docs/v5.4.x/Reference/Server/#return503onclosing)
* [`ajv`](https://fastify.dev/docs/v5.4.x/Reference/Server/#ajv)
* [`serializerOpts`](https://fastify.dev/docs/v5.4.x/Reference/Server/#serializeropts)
* [`http2SessionTimeout`](https://fastify.dev/docs/v5.4.x/Reference/Server/#http2sessiontimeout)
* [`frameworkErrors`](https://fastify.dev/docs/v5.4.x/Reference/Server/#frameworkerrors)
* [`clientErrorHandler`](https://fastify.dev/docs/v5.4.x/Reference/Server/#clienterrorhandler)
* [`rewriteUrl`](https://fastify.dev/docs/v5.4.x/Reference/Server/#rewriteurl)
* [`useSemicolonDelimiter`](https://fastify.dev/docs/v5.4.x/Reference/Server/#usesemicolondelimiter)
* [`allowErrorHandlerOverride`](https://fastify.dev/docs/v5.4.x/Reference/Server/#allowerrorhandleroverride)
* [Instance](https://fastify.dev/docs/v5.4.x/Reference/Server/#instance)
* [Server Methods](https://fastify.dev/docs/v5.4.x/Reference/Server/#server-methods)
* [`listenTextResolver`](https://fastify.dev/docs/v5.4.x/Reference/Server/#listentextresolver)
* [listeningOrigin](https://fastify.dev/docs/v5.4.x/Reference/Server/#listeningorigin)
---
# Request | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Request/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Request/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Request[](https://fastify.dev/docs/v5.3.x/Reference/Request/#request "Direct link to Request")
------------------------------------------------------------------------------------------------
The first parameter of the handler function is `Request`.
Request is a core Fastify object containing the following fields:
* `query` - The parsed querystring, its format is specified by [`querystringParser`](https://fastify.dev/docs/v5.3.x/Reference/Server/#querystringparser)
.
* `body` - The request payload, see [Content-Type Parser](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/)
for details on what request payloads Fastify natively parses and how to support other content types.
* `params` - The params matching the URL.
* [`headers`](https://fastify.dev/docs/v5.3.x/Reference/Request/#headers)
- The headers getter and setter.
* `raw` - The incoming HTTP request from Node core.
* `server` - The Fastify server instance, scoped to the current [encapsulation context](https://fastify.dev/docs/v5.3.x/Reference/Encapsulation/)
.
* `id` - The request ID.
* `log` - The logger instance of the incoming request.
* `ip` - The IP address of the incoming request.
* `ips` - An array of the IP addresses, ordered from closest to furthest, in the `X-Forwarded-For` header of the incoming request (only when the [`trustProxy`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-trust-proxy)
option is enabled).
* `host` - The host of the incoming request (derived from `X-Forwarded-Host` header when the [`trustProxy`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-trust-proxy)
option is enabled). For HTTP/2 compatibility, it returns `:authority` if no host header exists. The host header may return an empty string if `requireHostHeader` is `false`, not provided with HTTP/1.0, or removed by schema validation.
* `hostname` - The hostname derived from the `host` property of the incoming request.
* `port` - The port from the `host` property, which may refer to the port the server is listening on.
* `protocol` - The protocol of the incoming request (`https` or `http`).
* `method` - The method of the incoming request.
* `url` - The URL of the incoming request.
* `originalUrl` - Similar to `url`, allows access to the original `url` in case of internal re-routing.
* `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
* `socket` - The underlying connection of the incoming request.
* `context` - Deprecated, use `request.routeOptions.config` instead. A Fastify internal object. Do not use or modify it directly. It is useful to access one special key:
* `context.config` - The route [`config`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-config)
object.
* `routeOptions` - The route [`option`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-options)
object.
* `bodyLimit` - Either server limit or route limit.
* `config` - The [`config`](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-config)
object for this route.
* `method` - The HTTP method for the route.
* `url` - The path of the URL to match this route.
* `handler` - The handler for this route.
* `attachValidation` - Attach `validationError` to request (if there is a schema defined).
* `logLevel` - Log level defined for this route.
* `schema` - The JSON schemas definition for this route.
* `version` - A semver compatible string that defines the version of the endpoint.
* `exposeHeadRoute` - Creates a sibling HEAD route for any GET routes.
* `prefixTrailingSlash` - String used to determine how to handle passing `/` as a route with a prefix.
* [.getValidationFunction(schema | httpPart)](https://fastify.dev/docs/v5.3.x/Reference/Request/#getvalidationfunction)
- Returns a validation function for the specified schema or HTTP part, if set or cached.
* [.compileValidationSchema(schema, \[httpPart\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#compilevalidationschema)
- Compiles the specified schema and returns a validation function using the default (or customized) `ValidationCompiler`. The optional `httpPart` is forwarded to the `ValidationCompiler` if provided, defaults to `null`.
* [.validateInput(data, schema | httpPart, \[httpPart\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#validate)
- Validates the input using the specified schema and returns the serialized payload. If `httpPart` is provided, the function uses the serializer for that HTTP Status Code. Defaults to `null`.
### Headers[](https://fastify.dev/docs/v5.3.x/Reference/Request/#headers "Direct link to Headers")
The `request.headers` is a getter that returns an object with the headers of the incoming request. Set custom headers as follows:
request.headers = { 'foo': 'bar', 'baz': 'qux'}
This operation adds new values to the request headers, accessible via `request.headers.bar`. Standard request headers remain accessible via `request.raw.headers`.
For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added to headers on `not found` routes.
> 🛈 Note: Schema validation may mutate the `request.headers` and `request.raw.headers` objects, causing the headers to become empty.
fastify.post('/:params', options, function (request, reply) { console.log(request.body) console.log(request.query) console.log(request.params) console.log(request.headers) console.log(request.raw) console.log(request.server) console.log(request.id) console.log(request.ip) console.log(request.ips) console.log(request.host) console.log(request.hostname) console.log(request.port) console.log(request.protocol) console.log(request.url) console.log(request.routeOptions.method) console.log(request.routeOptions.bodyLimit) console.log(request.routeOptions.method) console.log(request.routeOptions.url) console.log(request.routeOptions.attachValidation) console.log(request.routeOptions.logLevel) console.log(request.routeOptions.version) console.log(request.routeOptions.exposeHeadRoute) console.log(request.routeOptions.prefixTrailingSlash) console.log(request.routeOptions.logLevel) request.log.info('some info')})
### .getValidationFunction(schema | httpPart)[](https://fastify.dev/docs/v5.3.x/Reference/Request/#getvalidationfunctionschema--httppart "Direct link to .getValidationFunction(schema | httpPart)")
By calling this function with a provided `schema` or `httpPart`, it returns a `validation` function to validate diverse inputs. It returns `undefined` if no serialization function is found using the provided inputs.
This function has an `errors` property. Errors encountered during the last validation are assigned to `errors`.
const validate = request .getValidationFunction({ type: 'object', properties: { foo: { type: 'string' } } })console.log(validate({ foo: 'bar' })) // trueconsole.log(validate.errors) // null// orconst validate = request .getValidationFunction('body')console.log(validate({ foo: 0.5 })) // falseconsole.log(validate.errors) // validation errors
See [.compileValidationSchema(schema, \[httpStatus\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#compileValidationSchema)
for more information on compiling validation schemas.
### .compileValidationSchema(schema, \[httpPart\])[](https://fastify.dev/docs/v5.3.x/Reference/Request/#compilevalidationschemaschema-httppart "Direct link to .compileValidationSchema(schema, [httpPart])")
This function compiles a validation schema and returns a function to validate data. The returned function (a.k.a. _validation function_) is compiled using the provided [`SchemaController#ValidationCompiler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#schema-controller)
. A `WeakMap` is used to cache this, reducing compilation calls.
The optional parameter `httpPart`, if provided, is forwarded to the `ValidationCompiler`, allowing it to compile the validation function if a custom `ValidationCompiler` is provided for the route.
This function has an `errors` property. Errors encountered during the last validation are assigned to `errors`.
const validate = request .compileValidationSchema({ type: 'object', properties: { foo: { type: 'string' } } })console.log(validate({ foo: 'bar' })) // trueconsole.log(validate.errors) // null// orconst validate = request .compileValidationSchema({ type: 'object', properties: { foo: { type: 'string' } } }, 200)console.log(validate({ hello: 'world' })) // falseconsole.log(validate.errors) // validation errors
Be careful when using this function, as it caches compiled validation functions based on the provided schema. If schemas are mutated or changed, the validation functions will not detect the alterations and will reuse the previously compiled validation function, as the cache is based on the schema's reference.
If schema properties need to be changed, create a new schema object to benefit from the cache mechanism.
Using the following schema as an example:
const schema1 = { type: 'object', properties: { foo: { type: 'string' } }}
_Not_
const validate = request.compileValidationSchema(schema1)// Later on...schema1.properties.foo.type. = 'integer'const newValidate = request.compileValidationSchema(schema1)console.log(newValidate === validate) // true
_Instead_
const validate = request.compileValidationSchema(schema1)// Later on...const newSchema = Object.assign({}, schema1)newSchema.properties.foo.type = 'integer'const newValidate = request.compileValidationSchema(newSchema)console.log(newValidate === validate) // false
### .validateInput(data, \[schema | httpStatus\], \[httpStatus\])[](https://fastify.dev/docs/v5.3.x/Reference/Request/#validateinputdata-schema--httpstatus-httpstatus "Direct link to .validateInput(data, [schema | httpStatus], [httpStatus])")
This function validates the input based on the provided schema or HTTP part. If both are provided, the `httpPart` parameter takes precedence.
If no validation function exists for a given `schema`, a new validation function will be compiled, forwarding the `httpPart` if provided.
request .validateInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }) // true// orrequest .validateInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }, 'body') // true// orrequest .validateInput({ hello: 'world'}, 'query') // false
See [.compileValidationSchema(schema, \[httpStatus\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#compileValidationSchema)
for more information on compiling validation schemas.
* [Request](https://fastify.dev/docs/v5.3.x/Reference/Request/#request)
* [Headers](https://fastify.dev/docs/v5.3.x/Reference/Request/#headers)
* [.getValidationFunction(schema | httpPart)](https://fastify.dev/docs/v5.3.x/Reference/Request/#getvalidationfunctionschema--httppart)
* [.compileValidationSchema(schema, \[httpPart\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#compilevalidationschemaschema-httppart)
* [.validateInput(data, \[schema | httpStatus\], \[httpStatus\])](https://fastify.dev/docs/v5.3.x/Reference/Request/#validateinputdata-schema--httpstatus-httpstatus)
---
# Warnings | Fastify
[Skip to main content](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#__docusaurus_skipToContent_fallback)
Version: v5.4.x
On this page
**Table of contents**
* [Warnings](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings)
* [Warnings In Fastify](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings-in-fastify)
* [Fastify Warning Codes](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-warning-codes)
* [FSTWRN001](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#FSTWRN001)
* [FSTWRN002](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#FSTWRN002)
* [Fastify Deprecation Codes](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-deprecation-codes)
Warnings[](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings "Direct link to Warnings")
----------------------------------------------------------------------------------------------------
### Warnings In Fastify[](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings-in-fastify "Direct link to Warnings In Fastify")
Fastify uses Node.js's [warning event](https://nodejs.org/api/process.html#event-warning)
API to notify users of deprecated features and coding mistakes. Fastify's warnings are recognizable by the `FSTWRN` and `FSTDEP` prefixes. When encountering such a warning, it is highly recommended to determine the cause using the [`--trace-warnings`](https://nodejs.org/api/cli.html#--trace-warnings)
and [`--trace-deprecation`](https://nodejs.org/api/cli.html#--trace-deprecation)
flags. These produce stack traces pointing to where the issue occurs in the application's code. Issues opened about warnings without this information will be closed due to lack of details.
Warnings can also be disabled, though it is not recommended. If necessary, use one of the following methods:
* Set the `NODE_NO_WARNINGS` environment variable to `1`
* Pass the `--no-warnings` flag to the node process
* Set `no-warnings` in the `NODE_OPTIONS` environment variable
For more information on disabling warnings, see [Node's documentation](https://nodejs.org/api/cli.html)
.
Disabling warnings may cause issues when upgrading Fastify versions. Only experienced users should consider disabling warnings.
### Fastify Warning Codes[](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-warning-codes "Direct link to Fastify Warning Codes")
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
| FSTWRN001 | The specified schema for a route is missing. This may indicate the schema is not well specified. | Check the schema for the route. | [#4647](https://github.com/fastify/fastify/pull/4647) |
| FSTWRN002 | The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`. | Do not mix async and callback style. | [#5139](https://github.com/fastify/fastify/pull/5139) |
### Fastify Deprecation Codes[](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-deprecation-codes "Direct link to Fastify Deprecation Codes")
Deprecation codes are supported by the Node.js CLI options:
* [\--no-deprecation](https://nodejs.org/api/cli.html#--no-deprecation)
* [\--throw-deprecation](https://nodejs.org/api/cli.html#--throw-deprecation)
* [\--trace-deprecation](https://nodejs.org/api/cli.html#--trace-deprecation)
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
* [Warnings](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings)
* [Warnings In Fastify](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#warnings-in-fastify)
* [Fastify Warning Codes](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-warning-codes)
* [Fastify Deprecation Codes](https://fastify.dev/docs/v5.4.x/Reference/Warnings/#fastify-deprecation-codes)
---
# Routes | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Routes/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Routes/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Routes[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes "Direct link to Routes")
--------------------------------------------------------------------------------------------
The route methods configure the endpoints of the application. Routes can be declared using the shorthand method or the full declaration.
* [Full declaration](https://fastify.dev/docs/v5.3.x/Reference/Routes/#full-declaration)
* [Routes options](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-options)
* [Shorthand declaration](https://fastify.dev/docs/v5.3.x/Reference/Routes/#shorthand-declaration)
* [Url building](https://fastify.dev/docs/v5.3.x/Reference/Routes/#url-building)
* [Async Await](https://fastify.dev/docs/v5.3.x/Reference/Routes/#async-await)
* [Promise resolution](https://fastify.dev/docs/v5.3.x/Reference/Routes/#promise-resolution)
* [Route Prefixing](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing)
* [Handling of / route inside prefixed plugins](https://fastify.dev/docs/v5.3.x/Reference/Routes/#handling-of--route-inside-prefixed-plugins)
* [Custom Log Level](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-level)
* [Custom Log Serializer](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-serializer)
* [Config](https://fastify.dev/docs/v5.3.x/Reference/Routes/#config)
* [Constraints](https://fastify.dev/docs/v5.3.x/Reference/Routes/#constraints)
* [Version Constraints](https://fastify.dev/docs/v5.3.x/Reference/Routes/#version-constraints)
* [Host Constraints](https://fastify.dev/docs/v5.3.x/Reference/Routes/#host-constraints)
### Full declaration[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#full-declaration "Direct link to Full declaration")
fastify.route(options)
### Routes options[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-options "Direct link to Routes options")
* `method`: currently it supports `GET`, `HEAD`, `TRACE`, `DELETE`, `OPTIONS`, `PATCH`, `PUT` and `POST`. To accept more methods, the [`addHttpMethod`](https://fastify.dev/docs/v5.3.x/Reference/Server/#addHttpMethod)
must be used. It could also be an array of methods.
* `url`: the path of the URL to match this route (alias: `path`).
* `schema`: an object containing the schemas for the request and response. They need to be in [JSON Schema](https://json-schema.org/)
format, check [here](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/)
for more info.
* `body`: validates the body of the request if it is a POST, PUT, PATCH, TRACE, SEARCH, PROPFIND, PROPPATCH or LOCK method.
* `querystring` or `query`: validates the querystring. This can be a complete JSON Schema object, with the property `type` of `object` and `properties` object of parameters, or simply the values of what would be contained in the `properties` object as shown below.
* `params`: validates the params.
* `response`: filter and generate a schema for the response, setting a schema allows us to have 10-20% more throughput.
* `exposeHeadRoute`: creates a sibling `HEAD` route for any `GET` routes. Defaults to the value of [`exposeHeadRoutes`](https://fastify.dev/docs/v5.3.x/Reference/Server/#exposeHeadRoutes)
instance option. If you want a custom `HEAD` handler without disabling this option, make sure to define it before the `GET` route.
* `attachValidation`: attach `validationError` to request, if there is a schema validation error, instead of sending the error to the error handler. The default [error format](https://ajv.js.org/api.html#error-objects)
is the Ajv one.
* `onRequest(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onrequest)
called as soon as a request is received, it could also be an array of functions.
* `preParsing(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
called before parsing the request, it could also be an array of functions.
* `preValidation(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prevalidation)
called after the shared `preValidation` hooks, useful if you need to perform authentication at route level for example, it could also be an array of functions.
* `preHandler(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#prehandler)
called just before the request handler, it could also be an array of functions.
* `preSerialization(request, reply, payload, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preserialization)
called just before the serialization, it could also be an array of functions.
* `onSend(request, reply, payload, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-hooks)
called right before a response is sent, it could also be an array of functions.
* `onResponse(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onresponse)
called when a response has been sent, so you will not be able to send more data to the client. It could also be an array of functions.
* `onTimeout(request, reply, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#ontimeout)
called when a request is timed out and the HTTP socket has been hung up.
* `onError(request, reply, error, done)`: a [function](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#onerror)
called when an Error is thrown or sent to the client by the route handler.
* `handler(request, reply)`: the function that will handle this request. The [Fastify server](https://fastify.dev/docs/v5.3.x/Reference/Server/)
will be bound to `this` when the handler is called. Note: using an arrow function will break the binding of `this`.
* `errorHandler(error, request, reply)`: a custom error handler for the scope of the request. Overrides the default error global handler, and anything set by [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
, for requests to the route. To access the default handler, you can access `instance.errorHandler`. Note that this will point to fastify's default `errorHandler` only if a plugin hasn't overridden it already.
* `childLoggerFactory(logger, binding, opts, rawReq)`: a custom factory function that will be called to produce a child logger instance for every request. See [`childLoggerFactory`](https://fastify.dev/docs/v5.3.x/Reference/Server/#childloggerfactory)
for more info. Overrides the default logger factory, and anything set by [`setChildLoggerFactory`](https://fastify.dev/docs/v5.3.x/Reference/Server/#setchildloggerfactory)
, for requests to the route. To access the default factory, you can access `instance.childLoggerFactory`. Note that this will point to Fastify's default `childLoggerFactory` only if a plugin hasn't overridden it already.
* `validatorCompiler({ schema, method, url, httpPart })`: function that builds schemas for request validations. See the [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schema-validator)
documentation.
* `serializerCompiler({ { schema, method, url, httpStatus, contentType } })`: function that builds schemas for response serialization. See the [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schema-serializer)
documentation.
* `schemaErrorFormatter(errors, dataVar)`: function that formats the errors from the validation compiler. See the [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#error-handling)
documentation. Overrides the global schema error formatter handler, and anything set by `setSchemaErrorFormatter`, for requests to the route.
* `bodyLimit`: prevents the default JSON body parser from parsing request bodies larger than this number of bytes. Must be an integer. You may also set this option globally when first creating the Fastify instance with `fastify(options)`. Defaults to `1048576` (1 MiB).
* `logLevel`: set log level for this route. See below.
* `logSerializers`: set serializers to log for this route.
* `config`: object used to store custom configuration.
* `version`: a [semver](https://semver.org/)
compatible string that defined the version of the endpoint. [Example](https://fastify.dev/docs/v5.3.x/Reference/Routes/#version-constraints)
.
* `constraints`: defines route restrictions based on request properties or values, enabling customized matching using [find-my-way](https://github.com/delvedor/find-my-way)
constraints. Includes built-in `version` and `host` constraints, with support for custom constraint strategies.
* `prefixTrailingSlash`: string used to determine how to handle passing `/` as a route with a prefix.
* `both` (default): Will register both `/prefix` and `/prefix/`.
* `slash`: Will register only `/prefix/`.
* `no-slash`: Will register only `/prefix`.
Note: this option does not override `ignoreTrailingSlash` in [Server](https://fastify.dev/docs/v5.3.x/Reference/Server/)
configuration.
* `request` is defined in [Request](https://fastify.dev/docs/v5.3.x/Reference/Request/)
.
* `reply` is defined in [Reply](https://fastify.dev/docs/v5.3.x/Reference/Reply/)
.
> 🛈 Note: The documentation for `onRequest`, `preParsing`, `preValidation`, `preHandler`, `preSerialization`, `onSend`, and `onResponse` is detailed in [Hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/)
> . To send a response before the request is handled by the `handler`, see [Respond to a request from a hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
> .
Example:
fastify.route({ method: 'GET', url: '/', schema: { querystring: { type: 'object', properties: { name: { type: 'string' }, excitement: { type: 'integer' } } }, response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})
### Shorthand declaration[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#shorthand-declaration "Direct link to Shorthand declaration")
The above route declaration is more _Hapi_\-like, but if you prefer an _Express/Restify_ approach, we support it as well:
`fastify.get(path, [options], handler)`
`fastify.head(path, [options], handler)`
`fastify.post(path, [options], handler)`
`fastify.put(path, [options], handler)`
`fastify.delete(path, [options], handler)`
`fastify.options(path, [options], handler)`
`fastify.patch(path, [options], handler)`
Example:
const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }}fastify.get('/', opts, (request, reply) => { reply.send({ hello: 'world' })})
`fastify.all(path, [options], handler)` will add the same handler to all the supported methods.
The handler may also be supplied via the `options` object:
const opts = { schema: { response: { 200: { type: 'object', properties: { hello: { type: 'string' } } } } }, handler: function (request, reply) { reply.send({ hello: 'world' }) }}fastify.get('/', opts)
> 🛈 Note: Specifying the handler in both `options` and as the third parameter to the shortcut method throws a duplicate `handler` error.
### Url building[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#url-building "Direct link to Url building")
Fastify supports both static and dynamic URLs.
To register a **parametric** path, use a _colon_ before the parameter name. For **wildcard**, use a _star_. Static routes are always checked before parametric and wildcard routes.
// parametricfastify.get('/example/:userId', function (request, reply) { // curl ${app-url}/example/12345 // userId === '12345' const { userId } = request.params; // your code here})fastify.get('/example/:userId/:secretToken', function (request, reply) { // curl ${app-url}/example/12345/abc.zHi // userId === '12345' // secretToken === 'abc.zHi' const { userId, secretToken } = request.params; // your code here})// wildcardfastify.get('/example/*', function (request, reply) {})
Regular expression routes are supported, but slashes must be escaped. Take note that RegExp is also very expensive in terms of performance!
// parametric with regexpfastify.get('/example/:file(^\\d+).png', function (request, reply) { // curl ${app-url}/example/12345.png // file === '12345' const { file } = request.params; // your code here})
It is possible to define more than one parameter within the same couple of slash ("/"). Such as:
fastify.get('/example/near/:lat-:lng/radius/:r', function (request, reply) { // curl ${app-url}/example/near/15°N-30°E/radius/20 // lat === "15°N" // lng === "30°E" // r ==="20" const { lat, lng, r } = request.params; // your code here})
_Remember in this case to use the dash ("-") as parameters separator._
Finally, it is possible to have multiple parameters with RegExp:
fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', function (request, reply) { // curl ${app-url}/example/at/08h24m // hour === "08" // minute === "24" const { hour, minute } = request.params; // your code here})
In this case as parameter separator it is possible to use whatever character is not matched by the regular expression.
The last parameter can be made optional by adding a question mark ("?") to the end of the parameter name.
fastify.get('/example/posts/:id?', function (request, reply) { const { id } = request.params; // your code here})
In this case, `/example/posts` and `/example/posts/1` are both valid. The optional param will be `undefined` if not specified.
Having a route with multiple parameters may negatively affect performance. Prefer a single parameter approach, especially on routes that are on the hot path of your application. For more details, see [find-my-way](https://github.com/delvedor/find-my-way)
.
To include a colon in a path without declaring a parameter, use a double colon. For example:
fastify.post('/name::verb') // will be interpreted as /name:verb
### Async Await[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#async-await "Direct link to Async Await")
Are you an `async/await` user? We have you covered!
fastify.get('/', options, async function (request, reply) { const data = await getData() const processed = await processData(data) return processed})
As shown, `reply.send` is not called to send data back to the user. Simply return the body and you are done!
If needed, you can also send data back with `reply.send`. In this case, do not forget to `return reply` or `await reply` in your `async` handler to avoid race conditions.
fastify.get('/', options, async function (request, reply) { const data = await getData() const processed = await processData(data) return reply.send(processed)})
If the route is wrapping a callback-based API that will call `reply.send()` outside of the promise chain, it is possible to `await reply`:
fastify.get('/', options, async function (request, reply) { setImmediate(() => { reply.send({ hello: 'world' }) }) await reply})
Returning reply also works:
fastify.get('/', options, async function (request, reply) { setImmediate(() => { reply.send({ hello: 'world' }) }) return reply})
> ⚠ Warning:
>
> * When using both `return value` and `reply.send(value)`, the first one takes precedence, the second is discarded, and a _warn_ log is emitted.
> * Calling `reply.send()` outside of the promise is possible but requires special attention. See [promise-resolution](https://fastify.dev/docs/v5.3.x/Reference/Routes/#promise-resolution)
> .
> * `undefined` cannot be returned. See [promise-resolution](https://fastify.dev/docs/v5.3.x/Reference/Routes/#promise-resolution)
> .
### Promise resolution[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#promise-resolution "Direct link to Promise resolution")
If the handler is an `async` function or returns a promise, be aware of the special behavior to support callback and promise control-flow. When the handler's promise resolves, the reply is automatically sent with its value unless you explicitly await or return `reply` in the handler.
1. If using `async/await` or promises but responding with `reply.send`:
* **Do** `return reply` / `await reply`.
* **Do not** forget to call `reply.send`.
2. If using `async/await` or promises:
* **Do not** use `reply.send`.
* **Do** return the value to send.
This approach supports both `callback-style` and `async-await` with minimal trade-off. However, it is recommended to use only one style for consistent error handling within your application.
> 🛈 Note: Every async function returns a promise by itself.
### Route Prefixing[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing "Direct link to Route Prefixing")
Sometimes maintaining multiple versions of the same API is necessary. A common approach is to prefix routes with the API version number, e.g., `/v1/user`. Fastify offers a fast and smart way to create different versions of the same API without changing all the route names by hand, called _route prefixing_. Here is how it works:
// server.jsconst fastify = require('fastify')()fastify.register(require('./routes/v1/users'), { prefix: '/v1' })fastify.register(require('./routes/v2/users'), { prefix: '/v2' })fastify.listen({ port: 3000 })
// routes/v1/users.jsmodule.exports = function (fastify, opts, done) { fastify.get('/user', handler_v1) done()}
// routes/v2/users.jsmodule.exports = function (fastify, opts, done) { fastify.get('/user', handler_v2) done()}
Fastify will not complain about using the same name for two different routes because it handles the prefix automatically at compilation time. This ensures performance is not affected.
Now clients will have access to the following routes:
* `/v1/user`
* `/v2/user`
This can be done multiple times and works for nested `register`. Route parameters are also supported.
To use a prefix for all routes, place them inside a plugin:
const fastify = require('fastify')()const route = { method: 'POST', url: '/login', handler: () => {}, schema: {},}fastify.register(function (app, _, done) { app.get('/users', () => {}) app.route(route) done()}, { prefix: '/v1' }) // global route prefixawait fastify.listen({ port: 3000 })
### Route Prefixing and fastify-plugin[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing-and-fastify-plugin "Direct link to Route Prefixing and fastify-plugin")
If using [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
to wrap routes, this option will not work. To make it work, wrap a plugin in a plugin:
const fp = require('fastify-plugin')const routes = require('./lib/routes')module.exports = fp(async function (app, opts) { app.register(routes, { prefix: '/v1', })}, { name: 'my-routes'})
#### Handling of / route inside prefixed plugins[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#handling-of--route-inside-prefixed-plugins "Direct link to Handling of / route inside prefixed plugins")
The `/` route behaves differently based on whether the prefix ends with `/`. For example, with a prefix `/something/`, adding a `/` route matches only `/something/`. With a prefix `/something`, adding a `/` route matches both `/something` and `/something/`.
See the `prefixTrailingSlash` route option above to change this behavior.
### Custom Log Level[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-level "Direct link to Custom Log Level")
Different log levels can be set for routes in Fastify by passing the `logLevel` option to the plugin or route with the desired [value](https://github.com/pinojs/pino/blob/master/docs/api.md#level-string)
.
Be aware that setting `logLevel` at the plugin level also affects [`setNotFoundHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#setnotfoundhandler)
and [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
.
// server.jsconst fastify = require('fastify')({ logger: true })fastify.register(require('./routes/user'), { logLevel: 'warn' })fastify.register(require('./routes/events'), { logLevel: 'debug' })fastify.listen({ port: 3000 })
Or pass it directly to a route:
fastify.get('/', { logLevel: 'warn' }, (request, reply) => { reply.send({ hello: 'world' })})
_Remember that the custom log level applies only to routes, not to the global Fastify Logger, accessible with `fastify.log`._
### Custom Log Serializer[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-serializer "Direct link to Custom Log Serializer")
In some contexts, logging a large object may waste resources. Define custom [`serializers`](https://github.com/pinojs/pino/blob/master/docs/api.md#serializers-object)
and attach them in the appropriate context.
const fastify = require('fastify')({ logger: true })fastify.register(require('./routes/user'), { logSerializers: { user: (value) => `My serializer one - ${value.name}` }})fastify.register(require('./routes/events'), { logSerializers: { user: (value) => `My serializer two - ${value.name} ${value.surname}` }})fastify.listen({ port: 3000 })
Serializers can be inherited by context:
const fastify = Fastify({ logger: { level: 'info', serializers: { user (req) { return { method: req.method, url: req.url, headers: req.headers, host: req.host, remoteAddress: req.ip, remotePort: req.socket.remotePort } } } }})fastify.register(context1, { logSerializers: { user: value => `My serializer father - ${value}` }})async function context1 (fastify, opts) { fastify.get('/', (req, reply) => { req.log.info({ user: 'call father serializer', key: 'another key' }) // shows: { user: 'My serializer father - call father serializer', key: 'another key' } reply.send({}) })}fastify.listen({ port: 3000 })
### Config[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#config "Direct link to Config")
Registering a new handler, you can pass a configuration object to it and retrieve it in the handler.
// server.jsconst fastify = require('fastify')()function handler (req, reply) { reply.send(reply.routeOptions.config.output)}fastify.get('/en', { config: { output: 'hello world!' } }, handler)fastify.get('/it', { config: { output: 'ciao mondo!' } }, handler)fastify.listen({ port: 3000 })
### Constraints[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#constraints "Direct link to Constraints")
Fastify supports constraining routes to match certain requests based on properties like the `Host` header or any other value via [`find-my-way`](https://github.com/delvedor/find-my-way)
constraints. Constraints are specified in the `constraints` property of the route options. Fastify has two built-in constraints: `version` and `host`. Custom constraint strategies can be added to inspect other parts of a request to decide if a route should be executed.
#### Version Constraints[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#version-constraints "Direct link to Version Constraints")
You can provide a `version` key in the `constraints` option to a route. Versioned routes allows multiple handlers to be declared for the same HTTP route path, matched according to the request's `Accept-Version` header. The `Accept-Version` header value should follow the [semver](https://semver.org/)
specification, and routes should be declared with exact semver versions for matching.
Fastify will require a request `Accept-Version` header to be set if the route has a version set, and will prefer a versioned route to a non-versioned route for the same path. Advanced version ranges and pre-releases currently are not supported.
_Be aware that using this feature will cause a degradation of the overall performances of the router._
fastify.route({ method: 'GET', url: '/', constraints: { version: '1.2.0' }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})fastify.inject({ method: 'GET', url: '/', headers: { 'Accept-Version': '1.x' // it could also be '1.2.0' or '1.2.x' }}, (err, res) => { // { hello: 'world' }})
> ⚠ Warning: Set a [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary)
> header in responses with the value used for versioning (e.g., `'Accept-Version'`) to prevent cache poisoning attacks. This can also be configured in a Proxy/CDN.
>
> const append = require('vary').appendfastify.addHook('onSend', (req, reply, payload, done) => { if (req.headers['accept-version']) { // or the custom header being used let value = reply.getHeader('Vary') || '' const header = Array.isArray(value) ? value.join(', ') : String(value) if ((value = append(header, 'Accept-Version'))) { // or the custom header being used reply.header('Vary', value) } } done()})
If multiple versions with the same major or minor are declared, Fastify will always choose the highest compatible with the `Accept-Version` header value.
If the request lacks an `Accept-Version` header, a 404 error will be returned.
Custom version matching logic can be defined through the [`constraints`](https://fastify.dev/docs/v5.3.x/Reference/Server/#constraints)
configuration when creating a Fastify server instance.
#### Host Constraints[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#host-constraints "Direct link to Host Constraints")
Provide a `host` key in the `constraints` route option to limit the route to certain values of the request `Host` header. `host` constraint values can be specified as strings for exact matches or RegExps for arbitrary host matching.
fastify.route({ method: 'GET', url: '/', constraints: { host: 'auth.fastify.dev' }, handler: function (request, reply) { reply.send('hello world from auth.fastify.dev') }})fastify.inject({ method: 'GET', url: '/', headers: { 'Host': 'example.com' }}, (err, res) => { // 404 because the host doesn't match the constraint})fastify.inject({ method: 'GET', url: '/', headers: { 'Host': 'auth.fastify.dev' }}, (err, res) => { // => 'hello world from auth.fastify.dev'})
RegExp `host` constraints can also be specified allowing constraining to hosts matching wildcard subdomains (or any other pattern):
fastify.route({ method: 'GET', url: '/', constraints: { host: /.*\.fastify\.dev/ }, // will match any subdomain of fastify.dev handler: function (request, reply) { reply.send('hello world from ' + request.headers.host) }})
#### Asynchronous Custom Constraints[](https://fastify.dev/docs/v5.3.x/Reference/Routes/#asynchronous-custom-constraints "Direct link to Asynchronous Custom Constraints")
Custom constraints can be provided, and the `constraint` criteria can be fetched from another source such as a database. Use asynchronous custom constraints as a last resort, as they impact router performance.
function databaseOperation(field, done) { done(null, field)}const secret = { // strategy name for referencing in the route handler `constraints` options name: 'secret', // storage factory for storing routes in the find-my-way route tree storage: function () { let handlers = {} return { get: (type) => { return handlers[type] || null }, set: (type, store) => { handlers[type] = store } } }, // function to get the value of the constraint from each incoming request deriveConstraint: (req, ctx, done) => { databaseOperation(req.headers['secret'], done) }, // optional flag marking if handlers without constraints can match requests that have a value for this constraint mustMatchWhenDerived: true}
> ⚠ Warning: When using asynchronous constraints, avoid returning errors inside the callback. If errors are unavoidable, provide a custom `frameworkErrors` handler to manage them. Otherwise, route selection may break or expose sensitive information.
>
> const Fastify = require('fastify')const fastify = Fastify({ frameworkErrors: function (err, res, res) { if (err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) { res.code(400) return res.send("Invalid header provided") } else { res.send(err) } }})
* [Routes](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes)
* [Full declaration](https://fastify.dev/docs/v5.3.x/Reference/Routes/#full-declaration)
* [Routes options](https://fastify.dev/docs/v5.3.x/Reference/Routes/#routes-options)
* [Shorthand declaration](https://fastify.dev/docs/v5.3.x/Reference/Routes/#shorthand-declaration)
* [Url building](https://fastify.dev/docs/v5.3.x/Reference/Routes/#url-building)
* [Async Await](https://fastify.dev/docs/v5.3.x/Reference/Routes/#async-await)
* [Promise resolution](https://fastify.dev/docs/v5.3.x/Reference/Routes/#promise-resolution)
* [Route Prefixing](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing)
* [Route Prefixing and fastify-plugin](https://fastify.dev/docs/v5.3.x/Reference/Routes/#route-prefixing-and-fastify-plugin)
* [Custom Log Level](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-level)
* [Custom Log Serializer](https://fastify.dev/docs/v5.3.x/Reference/Routes/#custom-log-serializer)
* [Config](https://fastify.dev/docs/v5.3.x/Reference/Routes/#config)
* [Constraints](https://fastify.dev/docs/v5.3.x/Reference/Routes/#constraints)
---
# Type-Providers | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Type-Providers/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Type Providers[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#type-providers "Direct link to Type Providers")
----------------------------------------------------------------------------------------------------------------------------
Type Providers are a TypeScript feature that enables Fastify to infer type information from inline JSON Schema. They are an alternative to specifying generic arguments on routes and can reduce the need to keep associated types for each schema in a project.
### Providers[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#providers "Direct link to Providers")
Official Type Provider packages follow the `@fastify/type-provider-{provider-name}` naming convention. Several community providers are also available.
The following inference packages are supported:
* [`json-schema-to-ts`](https://github.com/ThomasAribart/json-schema-to-ts)
* [`typebox`](https://github.com/sinclairzx81/typebox)
* [`zod`](https://github.com/colinhacks/zod)
See also the Type Provider wrapper packages for each of the packages respectively:
* [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
* [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
* [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
(3rd party)
### Json Schema to Ts[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#json-schema-to-ts "Direct link to Json Schema to Ts")
The following sets up a `json-schema-to-ts` Type Provider:
$ npm i @fastify/type-provider-json-schema-to-ts
import fastify from 'fastify'import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'const server = fastify().withTypeProvider()server.get('/route', { schema: { querystring: { type: 'object', properties: { foo: { type: 'number' }, bar: { type: 'string' }, }, required: ['foo', 'bar'] } }}, (request, reply) => { // type Query = { foo: number, bar: string } const { foo, bar } = request.query // type safe!})
### TypeBox[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#typebox "Direct link to TypeBox")
The following sets up a TypeBox Type Provider:
$ npm i @fastify/type-provider-typebox
import fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { Type } from '@sinclair/typebox'const server = fastify().withTypeProvider()server.get('/route', { schema: { querystring: Type.Object({ foo: Type.Number(), bar: Type.String() }) }}, (request, reply) => { // type Query = { foo: number, bar: string } const { foo, bar } = request.query // type safe!})
See the [TypeBox documentation](https://github.com/sinclairzx81/typebox#validation)
for setting up AJV to work with TypeBox.
### Zod[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#zod "Direct link to Zod")
See [official documentation](https://github.com/turkerdev/fastify-type-provider-zod)
for Zod Type Provider instructions.
### Scoped Type-Provider[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#scoped-type-provider "Direct link to Scoped Type-Provider")
The provider types don't propagate globally. In encapsulated usage, one can remap the context to use one or more providers (for example, `typebox` and `json-schema-to-ts` can be used in the same application).
Example:
import Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'import { Type } from '@sinclair/typebox'const fastify = Fastify()function pluginWithTypebox(fastify: FastifyInstance, _opts, done): void { fastify.withTypeProvider() .get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { const { x, y, z } = req.body // type safe }); done()}function pluginWithJsonSchema(fastify: FastifyInstance, _opts, done): void { fastify.withTypeProvider() .get('/', { schema: { body: { type: 'object', properties: { x: { type: 'string' }, y: { type: 'number' }, z: { type: 'boolean' } }, } } }, (req) => { const { x, y, z } = req.body // type safe }); done()}fastify.register(pluginWithJsonSchema)fastify.register(pluginWithTypebox)
It is important to note that since the types do not propagate globally, it is currently not possible to avoid multiple registrations on routes when dealing with several scopes, as shown below:
import Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { Type } from '@sinclair/typebox'const server = Fastify().withTypeProvider()server.register(plugin1) // wrongserver.register(plugin2) // correctfunction plugin1(fastify: FastifyInstance, _opts, done): void { fastify.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // In a new scope, call `withTypeProvider` again to ensure it works const { x, y, z } = req.body }); done()}function plugin2(fastify: FastifyInstance, _opts, done): void { const server = fastify.withTypeProvider() server.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // works const { x, y, z } = req.body }); done()}
### Type Definition of FastifyInstance + TypeProvider[](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#type-definition-of-fastifyinstance--typeprovider "Direct link to Type Definition of FastifyInstance + TypeProvider")
When working with modules, use `FastifyInstance` with Type Provider generics. See the example below:
// index.tsimport Fastify from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'import { registerRoutes } from './routes'const server = Fastify().withTypeProvider()registerRoutes(server)server.listen({ port: 3000 })
// routes.tsimport { Type } from '@sinclair/typebox'import { FastifyInstance, FastifyBaseLogger, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerDefault} from 'fastify'import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'type FastifyTypebox = FastifyInstance< RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, FastifyBaseLogger, TypeBoxTypeProvider>;export function registerRoutes(fastify: FastifyTypebox): void { fastify.get('/', { schema: { body: Type.Object({ x: Type.String(), y: Type.Number(), z: Type.Boolean() }) } }, (req) => { // works const { x, y, z } = req.body });}
* [Type Providers](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#type-providers)
* [Providers](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#providers)
* [Json Schema to Ts](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#json-schema-to-ts)
* [TypeBox](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#typebox)
* [Zod](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#zod)
* [Scoped Type-Provider](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#scoped-type-provider)
* [Type Definition of FastifyInstance + TypeProvider](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/#type-definition-of-fastifyinstance--typeprovider)
---
# TypeScript | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/TypeScript/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
TypeScript[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#typescript "Direct link to TypeScript")
------------------------------------------------------------------------------------------------------------
The Fastify framework is written in vanilla JavaScript, and as such type definitions are not as easy to maintain; however, since version 2 and beyond, maintainers and contributors have put in a great effort to improve the types.
The type system was changed in Fastify version 3. The new type system introduces generic constraining and defaulting, plus a new way to define schema types such as a request body, querystring, and more! As the team works on improving framework and type definition synergy, sometimes parts of the API will not be typed or may be typed incorrectly. We encourage you to **contribute** to help us fill in the gaps. Just make sure to read our [`CONTRIBUTING.md`](https://github.com/fastify/fastify/blob/main/CONTRIBUTING.md)
file before getting started to make sure things go smoothly!
> The documentation in this section covers Fastify version 3.x typings
> Plugins may or may not include typings. See [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
> for more information. We encourage users to send pull requests to improve typings support.
🚨 Don't forget to install `@types/node`
Learn By Example[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#learn-by-example "Direct link to Learn By Example")
------------------------------------------------------------------------------------------------------------------------------
The best way to learn the Fastify type system is by example! The following four examples should cover the most common Fastify development cases. After the examples there is further, more detailed documentation for the type system.
### Getting Started[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#getting-started "Direct link to Getting Started")
This example will get you up and running with Fastify and TypeScript. It results in a blank http Fastify server.
1. Create a new npm project, install Fastify, and install typescript & Node.js types as peer dependencies:
npm init -ynpm i fastifynpm i -D typescript @types/node
2. Add the following lines to the `"scripts"` section of the `package.json`:
{ "scripts": { "build": "tsc -p tsconfig.json", "start": "node index.js" }}
3. Initialize a TypeScript configuration file:
npx tsc --init
or use one of the [recommended ones](https://github.com/tsconfig/bases#node-14-tsconfigjson)
.
_Note: Set `target` property in `tsconfig.json` to `es2017` or greater to avoid [FastifyDeprecation](https://github.com/fastify/fastify/issues/3284)
warning._
4. Create an `index.ts` file - this will contain the server code
5. Add the following code block to your file:
import fastify from 'fastify'const server = fastify()server.get('/ping', async (request, reply) => { return 'pong\n'})server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(1) } console.log(`Server listening at ${address}`)})
6. Run `npm run build` - this will compile `index.ts` into `index.js` which can be executed using Node.js. If you run into any errors please open an issue in [fastify/help](https://github.com/fastify/help/)
7. Run `npm run start` to run the Fastify server
8. You should see `Server listening at http://127.0.0.1:8080` in your console
9. Try out your server using `curl localhost:8080/ping`, it should return `pong` 🏓
🎉 You now have a working Typescript Fastify server! This example demonstrates the simplicity of the version 3.x type system. By default, the type system assumes you are using an `http` server. The later examples will demonstrate how to create more complex servers such as `https` and `http2`, how to specify route schemas, and more!
> For more examples on initializing Fastify with TypeScript (such as enabling HTTP2) check out the detailed API section [here](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
### Using Generics[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#using-generics "Direct link to Using Generics")
The type system heavily relies on generic properties to provide the most accurate development experience. While some may find the overhead a bit cumbersome, the tradeoff is worth it! This example will dive into implementing generic types for route schemas and the dynamic properties located on the route-level `request` object.
1. If you did not complete the previous example, follow steps 1-4 to get set up.
2. Inside `index.ts`, define three interfaces `IQuerystring`,`IHeaders` and `IReply`:
interface IQuerystring { username: string; password: string;}interface IHeaders { 'h-Custom': string;}interface IReply { 200: { success: boolean }; 302: { url: string }; '4xx': { error: string };}
3. Using the three interfaces, define a new API route and pass them as generics. The shorthand route methods (i.e. `.get`) accept a generic object `RouteGenericInterface` containing five named properties: `Body`, `Querystring`, `Params`, `Headers` and `Reply`. The interfaces `Body`, `Querystring`, `Params` and `Headers` will be passed down through the route method into the route method handler `request` instance and the `Reply` interface to the `reply` instance.
server.get<{ Querystring: IQuerystring, Headers: IHeaders, Reply: IReply}>('/auth', async (request, reply) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] // do something with request data // chaining .statusCode/.code calls with .send allows type narrowing. For example: // this works reply.code(200).send({ success: true }); // but this gives a type error reply.code(200).send('uh-oh'); // it even works for wildcards reply.code(404).send({ error: 'Not found' }); return `logged in!`})
4. Build and run the server code with `npm run build` and `npm run start`
5. Query the API
curl localhost:8080/auth?username=admin&password=Password123!
And it should return back `logged in!`
6. But wait there's more! The generic interfaces are also available inside route level hook methods. Modify the previous route by adding a `preValidation` hook:
server.get<{ Querystring: IQuerystring, Headers: IHeaders, Reply: IReply}>('/auth', { preValidation: (request, reply, done) => { const { username, password } = request.query done(username !== 'admin' ? new Error('Must be admin') : undefined) // only validate `admin` account }}, async (request, reply) => { const customerHeader = request.headers['h-Custom'] // do something with request data return `logged in!`})
7. Build and run and query with the `username` query string option set to anything other than `admin`. The API should now return a HTTP 500 error `{"statusCode":500,"error":"Internal Server Error","message":"Must be admin"}`
🎉 Good work, now you can define interfaces for each route and have strictly typed request and reply instances. Other parts of the Fastify type system rely on generic properties. Make sure to reference the detailed type system documentation below to learn more about what is available.
### JSON Schema[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#json-schema "Direct link to JSON Schema")
To validate your requests and responses you can use JSON Schema files. If you didn't know already, defining schemas for your Fastify routes can increase their throughput! Check out the [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/)
documentation for more info.
Also it has the advantage to use the defined type within your handlers (including pre-validation, etc.).
Here are some options on how to achieve this.
#### Fastify Type Providers[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastify-type-providers "Direct link to Fastify Type Providers")
Fastify offers two packages wrapping `json-schema-to-ts` and `typebox`:
* [`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
* [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
And a `zod` wrapper by a third party called [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
They simplify schema validation setup and you can read more about them in [Type Providers](https://fastify.dev/docs/v5.3.x/Reference/Type-Providers/)
page.
Below is how to setup schema validation using the `typebox`, `json-schema-to-typescript`, and `json-schema-to-ts` packages without type providers.
#### TypeBox[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#typebox "Direct link to TypeBox")
A useful library for building types and a schema at once is [TypeBox](https://www.npmjs.com/package/@sinclair/typebox)
. With TypeBox you define your schema within your code and use them directly as types or schemas as you need them.
When you want to use it for validation of some payload in a fastify route you can do it as follows:
1. Install `typebox` in your project.
npm i @sinclair/typebox
2. Define the schema you need with `Type` and create the respective type with `Static`.
import { Static, Type } from '@sinclair/typebox'export const User = Type.Object({ name: Type.String(), mail: Type.Optional(Type.String({ format: 'email' })),})export type UserType = Static
3. Use the defined type and schema during the definition of your route
import Fastify from 'fastify'// ...const fastify = Fastify()fastify.post<{ Body: UserType, Reply: UserType }>( '/', { schema: { body: User, response: { 200: User }, }, }, (request, reply) => { // The `name` and `mail` types are automatically inferred const { name, mail } = request.body; reply.status(200).send({ name, mail }); })
#### json-schema-to-typescript[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#json-schema-to-typescript "Direct link to json-schema-to-typescript")
In the last example we used Typebox to define the types and schemas for our route. Many users will already be using JSON Schemas to define these properties, and luckily there is a way to transform existing JSON Schemas into TypeScript interfaces!
1. If you did not complete the 'Getting Started' example, go back and follow steps 1-4 first.
2. Install the `json-schema-to-typescript` module:
npm i -D json-schema-to-typescript
3. Create a new folder called `schemas` and add two files `headers.json` and `querystring.json`. Copy and paste the following schema definitions into the respective files:
{ "title": "Headers Schema", "type": "object", "properties": { "h-Custom": { "type": "string" } }, "additionalProperties": false, "required": ["h-Custom"]}
{ "title": "Querystring Schema", "type": "object", "properties": { "username": { "type": "string" }, "password": { "type": "string" } }, "additionalProperties": false, "required": ["username", "password"]}
4. Add a `compile-schemas` script to the package.json:
{ "scripts": { "compile-schemas": "json2ts -i schemas -o types" } }
`json2ts` is a CLI utility included in `json-schema-to-typescript`. `schemas` is the input path, and `types` is the output path. 5. Run `npm run compile-schemas`. Two new files should have been created in the `types` directory. 6. Update `index.ts` to have the following code:
import fastify from 'fastify' // import json schemas as normal import QuerystringSchema from './schemas/querystring.json' import HeadersSchema from './schemas/headers.json' // import the generated interfaces import { QuerystringSchema as QuerystringSchemaInterface } from './types/querystring' import { HeadersSchema as HeadersSchemaInterface } from './types/headers' const server = fastify() server.get<{ Querystring: QuerystringSchemaInterface, Headers: HeadersSchemaInterface }>('/auth', { schema: { querystring: QuerystringSchema, headers: HeadersSchema }, preValidation: (request, reply, done) => { const { username, password } = request.query done(username !== 'admin' ? new Error('Must be admin') : undefined) } // or if using async // preValidation: async (request, reply) => { // const { username, password } = request.query // if (username !== "admin") throw new Error("Must be admin"); // } }, async (request, reply) => { const customerHeader = request.headers['h-Custom'] // do something with request data return `logged in!` }) server.route<{ Querystring: QuerystringSchemaInterface, Headers: HeadersSchemaInterface }>({ method: 'GET', url: '/auth2', schema: { querystring: QuerystringSchema, headers: HeadersSchema }, preHandler: (request, reply, done) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] done() }, handler: (request, reply) => { const { username, password } = request.query const customerHeader = request.headers['h-Custom'] reply.status(200).send({username}); } }) server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(0) } console.log(`Server listening at ${address}`) })
Pay special attention to the imports at the top of this file. It might seem redundant, but you need to import both the schema files and the generated interfaces.
Great work! Now you can make use of both JSON Schemas and TypeScript definitions.
#### json-schema-to-ts[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#json-schema-to-ts "Direct link to json-schema-to-ts")
If you do not want to generate types from your schemas, but want to use them directly from your code, you can use the package [json-schema-to-ts](https://www.npmjs.com/package/json-schema-to-ts)
.
You can install it as dev-dependency.
npm i -D json-schema-to-ts
In your code you can define your schema like a normal object. But be aware of making it _const_ like explained in the docs of the module.
const todo = { type: 'object', properties: { name: { type: 'string' }, description: { type: 'string' }, done: { type: 'boolean' }, }, required: ['name'],} as const; // don't forget to use const !
With the provided type `FromSchema` you can build a type from your schema and use it in your handler.
import { FromSchema } from "json-schema-to-ts";fastify.post<{ Body: FromSchema }>( '/todo', { schema: { body: todo, response: { 201: { type: 'string', }, }, } }, async (request, reply): Promise => { /* request.body has type { [x: string]: unknown; description?: string; done?: boolean; name: string; } */ request.body.name // will not throw type error request.body.notthere // will throw type error reply.status(201).send(); },);
### Plugins[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins "Direct link to Plugins")
One of Fastify's most distinguishable features is its extensive plugin ecosystem. Plugin types are fully supported, and take advantage of the [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)
pattern. This example is broken up into three parts: Creating a TypeScript Fastify Plugin, Creating Type Definitions for a Fastify Plugin, and Using a Fastify Plugin in a TypeScript Project.
#### Creating a TypeScript Fastify Plugin[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#creating-a-typescript-fastify-plugin "Direct link to Creating a TypeScript Fastify Plugin")
1. Initialize a new npm project and install required dependencies
npm init -ynpm i fastify fastify-pluginnpm i -D typescript @types/node
2. Add a `build` script to the `"scripts"` section and `'index.d.ts'` to the `"types"` section of the `package.json` file:
{ "types": "index.d.ts", "scripts": { "build": "tsc -p tsconfig.json" }}
3. Initialize a TypeScript configuration file:
npx typescript --init
Once the file is generated, enable the `"declaration"` option in the `"compilerOptions"` object.
{ "compilerOptions": { "declaration": true }}
4. Create an `index.ts` file - this will contain the plugin code
5. Add the following code to `index.ts`
import { FastifyPluginCallback, FastifyPluginAsync } from 'fastify'import fp from 'fastify-plugin'// using declaration merging, add your plugin props to the appropriate fastify interfaces// if prop type is defined here, the value will be typechecked when you call decorate{,Request,Reply}declare module 'fastify' { interface FastifyRequest { myPluginProp: string } interface FastifyReply { myPluginProp: number }}// define optionsexport interface MyPluginOptions { myPluginOption: string}// define plugin using callbacksconst myPluginCallback: FastifyPluginCallback = (fastify, options, done) => { fastify.decorateRequest('myPluginProp', 'super_secret_value') fastify.decorateReply('myPluginProp', options.myPluginOption) done()}// define plugin using promisesconst myPluginAsync: FastifyPluginAsync = async (fastify, options) => { fastify.decorateRequest('myPluginProp', 'super_secret_value') fastify.decorateReply('myPluginProp', options.myPluginOption)}// export plugin using fastify-pluginexport default fp(myPluginCallback, '3.x')// or// export default fp(myPluginAsync, '3.x')
6. Run `npm run build` to compile the plugin code and produce both a JavaScript source file and a type definition file.
7. With the plugin now complete you can \[publish to npm\] or use it locally.
> You do not _need_ to publish your plugin to npm to use it. You can include it in a Fastify project and reference it as you would any piece of code! As a TypeScript user, make sure the declaration override exists somewhere that will be included in your project compilation so the TypeScript interpreter can process it.
#### Creating Type Definitions for a Fastify Plugin[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#creating-type-definitions-for-a-fastify-plugin "Direct link to Creating Type Definitions for a Fastify Plugin")
This plugin guide is for Fastify plugins written in JavaScript. The steps outlined in this example are for adding TypeScript support for users consuming your plugin.
1. Initialize a new npm project and install required dependencies
npm init -ynpm i fastify-plugin
2. Create two files `index.js` and `index.d.ts`
3. Modify the package json to include these files under the `main` and `types` properties (the name does not have to be `index` explicitly, but it is recommended the files have the same name):
{ "main": "index.js", "types": "index.d.ts"}
4. Open `index.js` and add the following code:
// fastify-plugin is highly recommended for any plugin you writeconst fp = require('fastify-plugin')function myPlugin (instance, options, done) { // decorate the fastify instance with a custom function called myPluginFunc instance.decorate('myPluginFunc', (input) => { return input.toUpperCase() }) done()}module.exports = fp(myPlugin, { fastify: '5.x', name: 'my-plugin' // this is used by fastify-plugin to derive the property name})
5. Open `index.d.ts` and add the following code:
import { FastifyPluginCallback } from 'fastify'interface PluginOptions { //...}// Optionally, you can add any additional exports.// Here we are exporting the decorator we added.export interface myPluginFunc { (input: string): string}// Most importantly, use declaration merging to add the custom property to the Fastify type systemdeclare module 'fastify' { interface FastifyInstance { myPluginFunc: myPluginFunc }}// fastify-plugin automatically adds named export, so be sure to add also this type// the variable name is derived from `options.name` property if `module.exports.myPlugin` is missingexport const myPlugin: FastifyPluginCallback// fastify-plugin automatically adds `.default` property to the exported plugin. See the note belowexport default myPlugin
**Note**: [fastify-plugin](https://github.com/fastify/fastify-plugin)
v2.3.0 and newer, automatically adds `.default` property and a named export to the exported plugin. Be sure to `export default` and `export const myPlugin` in your typings to provide the best developer experience. For a complete example you can check out [@fastify/swagger](https://github.com/fastify/fastify-swagger/blob/main/index.d.ts)
.
With those files completed, the plugin is now ready to be consumed by any TypeScript project!
The Fastify plugin system enables developers to decorate the Fastify instance, and the request/reply instances. For more information check out this blog post on [Declaration Merging and Generic Inheritance](https://dev.to/ethanarrowood/is-declaration-merging-and-generic-inheritance-at-the-same-time-impossible-53cp)
.
#### Using a Plugin[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#using-a-plugin "Direct link to Using a Plugin")
Using a Fastify plugin in TypeScript is just as easy as using one in JavaScript. Import the plugin with `import/from` and you're all set -- except there is one exception users should be aware of.
Fastify plugins use declaration merging to modify existing Fastify type interfaces (check out the previous two examples for more details). Declaration merging is not very _smart_, meaning if the plugin type definition for a plugin is within the scope of the TypeScript interpreter, then the plugin types will be included **regardless** of if the plugin is being used or not. This is an unfortunate limitation of using TypeScript and is unavoidable as of right now.
However, there are a couple of suggestions to help improve this experience:
* Make sure the `no-unused-vars` rule is enabled in [ESLint](https://eslint.org/docs/rules/no-unused-vars)
and any imported plugin are actually being loaded.
* Use a module such as [depcheck](https://www.npmjs.com/package/depcheck)
or [npm-check](https://www.npmjs.com/package/npm-check)
to verify plugin dependencies are being used somewhere in your project.
Note that using `require` will not load the type definitions properly and may cause type errors. TypeScript can only identify the types that are directly imported into code, which means that you can use require inline with import on top. For example:
import 'plugin' // here will trigger the type augmentation.fastify.register(require('plugin'))
import plugin from 'plugin' // here will trigger the type augmentation.fastify.register(plugin)
Or even explicit config on tsconfig
{ "types": ["plugin"] // we force TypeScript to import the types}
Code Completion In Vanilla JavaScript[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#code-completion-in-vanilla-javascript "Direct link to Code Completion In Vanilla JavaScript")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Vanilla JavaScript can use the published types to provide code completion (e.g. [Intellisense](https://code.visualstudio.com/docs/editor/intellisense)
) by following the [TypeScript JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
.
For example:
/** @type {import('fastify').FastifyPluginAsync<{ optionA: boolean, optionB: string }>} */module.exports = async function (fastify, { optionA, optionB }) { fastify.get('/look', () => 'at me');}
API Type System Documentation[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#api-type-system-documentation "Direct link to API Type System Documentation")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
This section is a detailed account of all the types available to you in Fastify version 3.x
All `http`, `https`, and `http2` types are inferred from `@types/node`
[Generics](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#generics)
are documented by their default value as well as their constraint value(s). Read these articles for more information on TypeScript generics.
* [Generic Parameter Default](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#generic-parameter-defaults)
* [Generic Constraints](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints)
#### How to import[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#how-to-import "Direct link to How to import")
The Fastify API is powered by the `fastify()` method. In JavaScript you would import it using `const fastify = require('fastify')`. In TypeScript it is recommended to use the `import/from` syntax instead so types can be resolved. There are a couple supported import methods with the Fastify type system.
1. `import fastify from 'fastify'`
* Types are resolved but not accessible using dot notation
* Example:
import fastify from 'fastify'const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Gain access to types with destructuring:
import fastify, { FastifyInstance } from 'fastify'const f: FastifyInstance = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Destructuring also works for the main API method:
import { fastify, FastifyInstance } from 'fastify'const f: FastifyInstance = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
2. `import * as Fastify from 'fastify'`
* Types are resolved and accessible using dot notation
* Calling the main Fastify API method requires a slightly different syntax (see example)
* Example:
import * as Fastify from 'fastify'const f: Fastify.FastifyInstance = Fastify.fastify()f.listen({ port: 8080 }, () => { console.log('running') })
3. `const fastify = require('fastify')`
* This syntax is valid and will import fastify as expected; however, types will **not** be resolved
* Example:
const fastify = require('fastify')const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
* Destructuring is supported and will resolve types properly
const { fastify } = require('fastify')const f = fastify()f.listen({ port: 8080 }, () => { console.log('running') })
#### Generics[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#generics "Direct link to Generics")
Many type definitions share the same generic parameters; they are all documented, in detail, within this section.
Most definitions depend on `@types/node` modules `http`, `https`, and `http2`
##### RawServer[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver "Direct link to RawServer")
Underlying Node.js server type
Default: `http.Server`
Constraints: `http.Server`, `https.Server`, `http2.Http2Server`, `http2.Http2SecureServer`
Enforces generic parameters: [`RawRequest`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [`RawReply`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
##### RawRequest[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest "Direct link to RawRequest")
Underlying Node.js request type
Default: [`RawRequestDefaultExpression`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawrequestdefaultexpressionrawserver)
Constraints: `http.IncomingMessage`, `http2.Http2ServerRequest`
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
##### RawReply[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply "Direct link to RawReply")
Underlying Node.js response type
Default: [`RawReplyDefaultExpression`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawreplydefaultexpression)
Constraints: `http.ServerResponse`, `http2.Http2ServerResponse`
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
##### Logger[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger "Direct link to Logger")
Fastify logging utility
Default: [`FastifyLoggerOptions`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyloggeroptions)
Enforced by: [`RawServer`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
##### RawBody[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawbody "Direct link to RawBody")
A generic parameter for the content-type-parser methods.
Constraints: `string | Buffer`
* * *
#### Fastify[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastify "Direct link to Fastify")
##### fastify< [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger)
\>(opts?: [FastifyServerOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyserveroptions-rawserver-logger)
): [FastifyInstance](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyinstance)
[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastify-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance "Direct link to fastify-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L19)
The main Fastify API method. By default creates an HTTP server. Utilizing discriminant unions and overload methods, the type system will automatically infer which type of server (http, https, or http2) is being created purely based on the options based to the method (see the examples below for more information). It also supports an extensive generic type system to allow the user to extend the underlying Node.js Server, Request, and Reply objects. Additionally, the `Logger` generic exists for custom log types. See the examples and generic breakdown below for more information.
###### Example 1: Standard HTTP server[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-1-standard-http-server "Direct link to Example 1: Standard HTTP server")
No need to specify the `Server` generic as the type system defaults to HTTP.
import fastify from 'fastify'const server = fastify()
Check out the Learn By Example - [Getting Started](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#getting-started)
example for a more detailed http server walkthrough.
###### Example 2: HTTPS server[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-2-https-server "Direct link to Example 2: HTTPS server")
1. Create the following imports from `@types/node` and `fastify`
import fs from 'node:fs'import path from 'node:path'import fastify from 'fastify'
2. Perform the following steps before setting up a Fastify HTTPS server to create the `key.pem` and `cert.pem` files:
openssl genrsa -out key.pemopenssl req -new -key key.pem -out csr.pemopenssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pemrm csr.pem
3. Instantiate a Fastify https server and add a route:
const server = fastify({ https: { key: fs.readFileSync(path.join(__dirname, 'key.pem')), cert: fs.readFileSync(path.join(__dirname, 'cert.pem')) }})server.get('/', async function (request, reply) { return { hello: 'world' }})server.listen({ port: 8080 }, (err, address) => { if (err) { console.error(err) process.exit(0) } console.log(`Server listening at ${address}`)})
4. Build and run! Test your server out by querying with: `curl -k https://localhost:8080`
###### Example 3: HTTP2 server[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-3-http2-server "Direct link to Example 3: HTTP2 server")
There are two types of HTTP2 server types, insecure and secure. Both require specifying the `http2` property as `true` in the `options` object. The `https` property is used for creating a secure http2 server; omitting the `https` property will create an insecure http2 server.
const insecureServer = fastify({ http2: true })const secureServer = fastify({ http2: true, https: {} // use the `key.pem` and `cert.pem` files from the https section})
For more details on using HTTP2 check out the Fastify [HTTP2](https://fastify.dev/docs/v5.3.x/Reference/HTTP2/)
documentation page.
###### Example 4: Extended HTTP server[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-4-extended-http-server "Direct link to Example 4: Extended HTTP server")
Not only can you specify the server type, but also the request and reply types. Thus, allowing you to specify special properties, methods, and more! When specified at server instantiation, the custom type becomes available on all further instances of the custom type.
import fastify from 'fastify'import http from 'node:http'interface customRequest extends http.IncomingMessage { mySpecialProp: string}const server = fastify()server.get('/', async (request, reply) => { const someValue = request.raw.mySpecialProp // TS knows this is a string, because of the `customRequest` interface return someValue.toUpperCase()})
###### Example 5: Specifying logger types[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-5-specifying-logger-types "Direct link to Example 5: Specifying logger types")
Fastify uses [Pino](https://getpino.io/#/)
logging library under the hood. Since `pino@7`, all of it's properties can be configured via `logger` field when constructing Fastify's instance. If properties you need aren't exposed, please open an Issue to [`Pino`](https://github.com/pinojs/pino/issues)
or pass a preconfigured external instance of Pino (or any other compatible logger) as temporary fix to Fastify via the same field. This allows creating custom serializers as well, see the [Logging](https://fastify.dev/docs/v5.3.x/Reference/Logging/)
documentation for more info.
import fastify from 'fastify'const server = fastify({ logger: { level: 'info', redact: ['x-userinfo'], messageKey: 'message' }})server.get('/', async (request, reply) => { server.log.info('log message') return 'another message'})
* * *
##### fastify.HTTPMethods[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyhttpmethods "Direct link to fastify.HTTPMethods")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L8)
Union type of: `'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'OPTIONS'`
##### fastify.RawServerBase[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserverbase "Direct link to fastify.RawServerBase")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L13)
Dependent on `@types/node` modules `http`, `https`, `http2`
Union type of: `http.Server | https.Server | http2.Http2Server | http2.Http2SecureServer`
##### fastify.RawServerDefault[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserverdefault "Direct link to fastify.RawServerDefault")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L18)
Dependent on `@types/node` modules `http`
Type alias for `http.Server`
* * *
##### fastify.FastifyServerOptions< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [Logger](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyserveroptions-rawserver-logger "Direct link to fastifyfastifyserveroptions-rawserver-logger")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L29)
An interface of properties used in the instantiation of the Fastify server. Is used in the main [`fastify()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method. The `RawServer` and `Logger` generic parameters are passed down through that method.
See the main [fastify](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method type definition section for examples on instantiating a Fastify server with TypeScript.
##### fastify.FastifyInstance< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [Logger](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyinstance-rawserver-rawrequest-requestgeneric-logger "Direct link to fastifyfastifyinstance-rawserver-rawrequest-requestgeneric-logger")
[src](https://github.com/fastify/fastify/blob/main/types/instance.d.ts#L16)
Interface that represents the Fastify server object. This is the returned server instance from the [`fastify()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method. This type is an interface so it can be extended via [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)
if your code makes use of the `decorate` method.
Through the use of generic cascading, all methods attached to the instance inherit the generic properties from instantiation. This means that by specifying the server, request, or reply types, all methods will know how to type those objects.
Check out the main [Learn by Example](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#learn-by-example)
section for detailed guides, or the more simplified [fastify](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserver-rawrequest-rawreply-loggeropts-fastifyserveroptions-fastifyinstance)
method examples for additional details on this interface.
* * *
#### Request[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#request "Direct link to Request")
##### fastify.FastifyRequest< [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequest-requestgeneric-rawserver-rawrequest "Direct link to fastifyfastifyrequest-requestgeneric-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/request.d.ts#L15)
This interface contains properties of Fastify request object. The properties added here disregard what kind of request object (http vs http2) and disregard what route level it is serving; thus calling `request.body` inside a GET request will not throw an error (but good luck sending a GET request with a body 😉).
If you need to add custom properties to the `FastifyRequest` object (such as when using the \[`decorateRequest`\]\[DecorateRequest\] method) you need to use declaration merging on this interface.
A basic example is provided in the [`FastifyRequest`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
section. For a more detailed example check out the Learn By Example section: [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
###### Example[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example "Direct link to Example")
import fastify from 'fastify'const server = fastify()server.decorateRequest('someProp', 'hello!')server.get('/', async (request, reply) => { const { someProp } = request // need to use declaration merging to add this prop to the request interface return someProp})// this declaration must be in scope of the typescript interpreter to workdeclare module 'fastify' { interface FastifyRequest { // you must reference the interface and not the type someProp: string }}// Or you can type your request usingtype CustomRequest = FastifyRequest<{ Body: { test: boolean };}>server.get('/typedRequest', async (request: CustomRequest, reply: FastifyReply) => { return request.body.test})
##### fastify.RequestGenericInterface[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface "Direct link to fastify.RequestGenericInterface")
[src](https://github.com/fastify/fastify/blob/main/types/request.d.ts#L4)
Fastify request objects have four dynamic properties: `body`, `params`, `query`, and `headers`. Their respective types are assignable through this interface. It is a named property interface enabling the developer to ignore the properties they do not want to specify. All omitted properties are defaulted to `unknown`. The corresponding property names are: `Body`, `Querystring`, `Params`, `Headers`.
import fastify, { RequestGenericInterface } from 'fastify'const server = fastify()interface requestGeneric extends RequestGenericInterface { Querystring: { name: string }}server.get('/', async (request, reply) => { const { name } = request.query // the name prop now exists on the query prop return name.toUpperCase()})
If you want to see a detailed example of using this interface check out the Learn by Example section: [JSON Schema](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#json-schema)
.
##### fastify.RawRequestDefaultExpression< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawrequestdefaultexpression-rawserver "Direct link to fastifyrawrequestdefaultexpression-rawserver")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L23)
Dependent on `@types/node` modules `http`, `https`, `http2`
Generic parameter `RawServer` defaults to [`RawServerDefault`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserverdefault)
If `RawServer` is of type `http.Server` or `https.Server`, then this expression returns `http.IncomingMessage`, otherwise, it returns `http2.Http2ServerRequest`.
import http from 'node:http'import http2 from 'node:http2'import { RawRequestDefaultExpression } from 'fastify'RawRequestDefaultExpression // -> http.IncomingMessageRawRequestDefaultExpression // -> http2.Http2ServerRequest
* * *
#### Reply[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#reply "Direct link to Reply")
##### fastify.FastifyReply< [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreply-requestgeneric-rawserver-rawrequest-rawreply-contextconfig "Direct link to fastifyfastifyreply-requestgeneric-rawserver-rawrequest-rawreply-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/reply.d.ts#L32)
This interface contains the custom properties that Fastify adds to the standard Node.js reply object. The properties added here disregard what kind of reply object (http vs http2).
If you need to add custom properties to the FastifyReply object (such as when using the `decorateReply` method) you need to use declaration merging on this interface.
A basic example is provided in the [`FastifyReply`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
section. For a more detailed example check out the Learn By Example section: [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
###### Example[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-1 "Direct link to Example")
import fastify from 'fastify'const server = fastify()server.decorateReply('someProp', 'world')server.get('/', async (request, reply) => { const { someProp } = reply // need to use declaration merging to add this prop to the reply interface return someProp})// this declaration must be in scope of the typescript interpreter to workdeclare module 'fastify' { interface FastifyReply { // you must reference the interface and not the type someProp: string }}
##### fastify.RawReplyDefaultExpression< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawreplydefaultexpression-rawserver "Direct link to fastifyrawreplydefaultexpression-rawserver")
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L27)
Dependent on `@types/node` modules `http`, `https`, `http2`
Generic parameter `RawServer` defaults to [`RawServerDefault`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrawserverdefault)
If `RawServer` is of type `http.Server` or `https.Server`, then this expression returns `http.ServerResponse`, otherwise, it returns `http2.Http2ServerResponse`.
import http from 'node:http'import http2 from 'node:http2'import { RawReplyDefaultExpression } from 'fastify'RawReplyDefaultExpression // -> http.ServerResponseRawReplyDefaultExpression // -> http2.Http2ServerResponse
* * *
#### Plugin[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugin "Direct link to Plugin")
Fastify allows the user to extend its functionalities with plugins. A plugin can be a set of routes, a server decorator or whatever. To activate plugins, use the [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
When creating plugins for Fastify, it is recommended to use the `fastify-plugin` module. Additionally, there is a guide to creating plugins with TypeScript and Fastify available in the Learn by Example, [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
section.
##### fastify.FastifyPluginCallback< [Options](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyplugincallback-options "Direct link to fastifyfastifyplugincallback-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L9)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
##### fastify.FastifyPluginAsync< [Options](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginasync-options "Direct link to fastifyfastifypluginasync-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L20)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method.
##### fastify.FastifyPlugin< [Options](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyplugin-options "Direct link to fastifyfastifyplugin-options")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L29)
Interface method definition used within the [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
method. Document deprecated in favor of `FastifyPluginCallback` and `FastifyPluginAsync` since general `FastifyPlugin` doesn't properly infer types for async functions.
##### fastify.FastifyPluginOptions[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions "Direct link to fastify.FastifyPluginOptions")
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L31)
A loosely typed object used to constrain the `options` parameter of [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterrawserver-rawrequest-requestgenericplugin-fastifyplugin-opts-fastifyregisteroptions)
to an object. When creating a plugin, define its options as an extension of this interface (`interface MyPluginOptions extends FastifyPluginOptions`) so they can be passed to the register method.
* * *
#### Register[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#register "Direct link to Register")
##### fastify.FastifyRegister(plugin: [FastifyPluginCallback](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyplugincallbackoptions)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifyplugincallback-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifyplugincallback-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
##### fastify.FastifyRegister(plugin: [FastifyPluginAsync](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginasyncoptions)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifypluginasync-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifypluginasync-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
##### fastify.FastifyRegister(plugin: [FastifyPlugin](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions-rawserver-rawrequest-requestgeneric)
, opts: [FastifyRegisterOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifytregisteroptions)
)[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisterplugin-fastifyplugin-opts-fastifyregisteroptions "Direct link to fastifyfastifyregisterplugin-fastifyplugin-opts-fastifyregisteroptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L9)
This type interface specifies the type for the [`fastify.register()`](https://fastify.dev/docs/v5.3.x/Reference/Server/#register)
method. The type interface returns a function signature with an underlying generic `Options` which is defaulted to [FastifyPluginOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifypluginoptions)
. It infers this generic from the FastifyPlugin parameter when calling this function so there is no need to specify the underlying generic. The options parameter is the intersection of the plugin's options and two additional optional properties: `prefix: string` and `logLevel`: [LogLevel](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyloglevel)
. `FastifyPlugin` is deprecated use `FastifyPluginCallback` and `FastifyPluginAsync` instead.
Below is an example of the options inference in action:
const server = fastify()const plugin: FastifyPluginCallback<{ option1: string; option2: boolean;}> = function (instance, opts, done) { }server().register(plugin, {}) // Error - options object is missing required propertiesserver().register(plugin, { option1: '', option2: true }) // OK - options object contains required properties
See the Learn By Example, [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
section for more detailed examples of creating TypeScript plugins in Fastify.
##### fastify.FastifyRegisterOptions[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyregisteroptions "Direct link to fastify.FastifyRegisterOptions")
[src](https://github.com/fastify/fastify/blob/main/types/register.d.ts#L16)
This type is the intersection of the `Options` generic and a non-exported interface `RegisterOptions` that specifies two optional properties: `prefix: string` and `logLevel`: [LogLevel](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyloglevel)
. This type can also be specified as a function that returns the previously described intersection.
* * *
#### Logger[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger-1 "Direct link to Logger")
Check out the [Specifying Logger Types](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#example-5-specifying-logger-types)
example for more details on specifying a custom logger.
##### fastify.FastifyLoggerOptions< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyloggeroptions-rawserver-rawrequest-rawreply "Direct link to fastifyfastifyloggeroptions-rawserver-rawrequest-rawreply")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L17)
An interface definition for the internal Fastify logger. It is emulative of the [Pino.js](https://getpino.io/#/)
logger. When enabled through server options, use it following the general [logger](https://fastify.dev/docs/v5.3.x/Reference/Logging/)
documentation.
##### fastify.FastifyLogFn[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifylogfn "Direct link to fastify.FastifyLogFn")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L7)
An overload function interface that implements the two ways Fastify calls log methods. This interface is passed to all associated log level properties on the FastifyLoggerOptions object.
##### fastify.LogLevel[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyloglevel "Direct link to fastify.LogLevel")
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L12)
Union type of: `'info' | 'error' | 'debug' | 'fatal' | 'warn' | 'trace'`
* * *
#### Context[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#context "Direct link to Context")
The context type definition is similar to the other highly dynamic pieces of the type system. Route context is available in the route handler method.
##### fastify.FastifyRequestContext[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestcontext "Direct link to fastify.FastifyRequestContext")
[src](https://github.com/fastify/fastify/blob/main/types/context.d.ts#L11)
An interface with a single required property `config` that is set by default to `unknown`. Can be specified either using a generic or an overload.
This type definition is potentially incomplete. If you are using it and can provide more details on how to improve the definition, we strongly encourage you to open an issue in the main [fastify/fastify](https://github.com/fastify/fastify)
repository. Thank you in advanced!
##### fastify.FastifyReplyContext[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplycontext "Direct link to fastify.FastifyReplyContext")
[src](https://github.com/fastify/fastify/blob/main/types/context.d.ts#L11)
An interface with a single required property `config` that is set by default to `unknown`. Can be specified either using a generic or an overload.
This type definition is potentially incomplete. If you are using it and can provide more details on how to improve the definition, we strongly encourage you to open an issue in the main [fastify/fastify](https://github.com/fastify/fastify)
repository. Thank you in advanced!
* * *
#### Routing[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#routing "Direct link to Routing")
One of the core principles in Fastify is its routing capabilities. Most of the types defined in this section are used under-the-hood by the Fastify instance `.route` and `.get/.post/.etc` methods.
##### fastify.RouteHandlerMethod< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyroutehandlermethod-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyroutehandlermethod-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L105)
A type declaration for the route handler methods. Has two arguments, `request` and `reply` which are typed by `FastifyRequest` and `FastifyReply` respectively. The generics parameters are passed through to these arguments. The method returns either `void` or `Promise` for synchronous and asynchronous handlers respectively.
##### fastify.RouteOptions< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrouteoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L78)
An interface that extends RouteShorthandOptions and adds the following three required properties:
1. `method` which corresponds to a singular [HTTPMethod](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyhttpmethods)
or a list of [HTTPMethods](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyhttpmethods)
2. `url` a string for the route
3. `handler` the route handler method, see \[RouteHandlerMethod\]\[\] for more details
##### fastify.RouteShorthandMethod< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrouteshorthandmethod-rawserver-rawrequest-rawreply "Direct link to fastifyrouteshorthandmethod-rawserver-rawrequest-rawreply")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#12)
An overloaded function interface for three kinds of shorthand route methods to be used in conjunction with the `.get/.post/.etc` methods.
##### fastify.RouteShorthandOptions< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrouteshorthandoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteshorthandoptions-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#55)
An interface that covers all of the base options for a route. Each property on this interface is optional, and it serves as the base for the RouteOptions and RouteShorthandOptionsWithHandler interfaces.
##### fastify.RouteShorthandOptionsWithHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrouteshorthandoptionswithhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfig "Direct link to fastifyrouteshorthandoptionswithhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfig")
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#93)
This interface adds a single, required property to the RouteShorthandOptions interface `handler` which is of type RouteHandlerMethod
* * *
#### Parsers[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#parsers "Direct link to Parsers")
##### RawBody[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawbody-1 "Direct link to RawBody")
A generic type that is either a `string` or `Buffer`
##### fastify.FastifyBodyParser< [RawBody](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawbody)
, [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifybodyparser-rawbody-rawserver-rawrequest "Direct link to fastifyfastifybodyparser-rawbody-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L7)
A function type definition for specifying a body parser method. Use the `RawBody` generic to specify the type of the body being parsed.
##### fastify.FastifyContentTypeParser< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifycontenttypeparser-rawserver-rawrequest "Direct link to fastifyfastifycontenttypeparser-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L17)
A function type definition for specifying a body parser method. Content is typed via the `RawRequest` generic.
##### fastify.AddContentTypeParser< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
\>[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyaddcontenttypeparser-rawserver-rawrequest "Direct link to fastifyaddcontenttypeparser-rawserver-rawrequest")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L46)
An overloaded interface function definition for the `addContentTypeParser` method. If `parseAs` is passed to the `opts` parameter, the definition uses \[FastifyBodyParser\]\[\] for the `parser` parameter; otherwise, it uses \[FastifyContentTypeParser\]\[\].
##### fastify.hasContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyhascontenttypeparser "Direct link to fastify.hasContentTypeParser")
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L63)
A method for checking the existence of a type parser of a certain content type
* * *
#### Errors[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#errors "Direct link to Errors")
##### fastify.FastifyError[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror "Direct link to fastify.FastifyError")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L179)
FastifyError is a custom error object that includes status code and validation results.
It extends the Node.js `Error` type, and adds two additional, optional properties: `statusCode: number` and `validation: ValidationResult[]`.
##### fastify.ValidationResult[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyvalidationresult "Direct link to fastify.ValidationResult")
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L184)
The route validation internally relies upon Ajv, which is a high-performance JSON schema validator.
This interface is passed to instance of FastifyError.
* * *
#### Hooks[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#hooks "Direct link to Hooks")
##### fastify.onRequestHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonrequesthookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonrequesthookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L17)
`onRequest` is the first hook to be executed in the request lifecycle. There was no previous hook, the next hook will be `preParsing`.
Notice: in the `onRequest` hook, request.body will always be null, because the body parsing happens before the `preHandler` hook.
##### fastify.preParsingHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifypreparsinghookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifypreparsinghookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L35)
`preParsing` is the second hook to be executed in the request lifecycle. The previous hook was `onRequest`, the next hook will be `preValidation`.
Notice: in the `preParsing` hook, request.body will always be null, because the body parsing happens before the `preValidation` hook.
Notice: you should also add `receivedEncodedLength` property to the returned stream. This property is used to correctly match the request payload with the `Content-Length` header value. Ideally, this property should be updated on each received chunk.
##### fastify.preValidationHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyprevalidationhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyprevalidationhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L53)
`preValidation` is the third hook to be executed in the request lifecycle. The previous hook was `preParsing`, the next hook will be `preHandler`.
##### fastify.preHandlerHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyprehandlerhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyprehandlerhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L70)
`preHandler` is the fourth hook to be executed in the request lifecycle. The previous hook was `preValidation`, the next hook will be `preSerialization`.
##### fastify.preSerializationHookHandler< PreSerializationPayload, [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, payload: PreSerializationPayload, done: (err: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
| null, res?: unknown) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifypreserializationhookhandler-preserializationpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-preserializationpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void "Direct link to fastifypreserializationhookhandler-preserializationpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-preserializationpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L94)
`preSerialization` is the fifth hook to be executed in the request lifecycle. The previous hook was `preHandler`, the next hook will be `onSend`.
Note: the hook is NOT called if the payload is a string, a Buffer, a stream or null.
##### fastify.onSendHookHandler< OnSendPayload, [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, payload: OnSendPayload, done: (err: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
| null, res?: unknown) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonsendhookhandler-onsendpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-onsendpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void "Direct link to fastifyonsendhookhandler-onsendpayload-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-payload-onsendpayload-done-err-fastifyerror--null-res-unknown--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L114)
You can change the payload with the `onSend` hook. It is the sixth hook to be executed in the request lifecycle. The previous hook was `preSerialization`, the next hook will be `onResponse`.
Note: If you change the payload, you may only change it to a string, a Buffer, a stream, or null.
##### fastify.onResponseHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonresponsehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonresponsehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L134)
`onResponse` is the seventh and last hook in the request hook lifecycle. The previous hook was `onSend`, there is no next hook.
The onResponse hook is executed when a response has been sent, so you will not be able to send more data to the client. It can however be useful for sending data to external services, for example to gather statistics.
##### fastify.onErrorHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(request: [FastifyRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyrequestrawserver-rawrequest-requestgeneric)
, reply: [FastifyReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyreplyrawserver-rawreply-contextconfig)
, error: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
, done: () => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonerrorhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-error-fastifyerror-done---void-promiseunknown--void "Direct link to fastifyonerrorhookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigrequest-fastifyrequest-reply-fastifyreply-error-fastifyerror-done---void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L154)
This hook is useful if you need to do some custom error logging or add some specific header in case of error.
It is not intended for changing the error, and calling reply.send will throw an exception.
This hook will be executed only after the customErrorHandler has been executed, and only if the customErrorHandler sends an error back to the user (Note that the default customErrorHandler always sends the error back to the user).
Notice: unlike the other hooks, pass an error to the done function is not supported.
##### fastify.onRouteHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [RequestGeneric](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrequestgenericinterface)
, [ContextConfig](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#ContextConfigGeneric)
\>(opts: [RouteOptions](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyrouteoptionsrawserver-rawrequest-rawreply-requestgeneric-contextconfig)
& { path: string; prefix: string }): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonroutehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigopts-routeoptions---path-string-prefix-string--promiseunknown--void "Direct link to fastifyonroutehookhandler-rawserver-rawrequest-rawreply-requestgeneric-contextconfigopts-routeoptions---path-string-prefix-string--promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L174)
Triggered when a new route is registered. Listeners are passed a routeOptions object as the sole parameter. The interface is synchronous, and, as such, the listener does not get passed a callback
##### fastify.onRegisterHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger)
\>(instance: [FastifyInstance](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyinstance)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonregisterhookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonregisterhookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L191)
Triggered when a new plugin is registered and a new encapsulation context is created. The hook will be executed before the registered code.
This hook can be useful if you are developing a plugin that needs to know when a plugin context is formed, and you want to operate in that specific context.
Note: This hook will not be called if a plugin is wrapped inside fastify-plugin.
##### fastify.onCloseHookHandler< [RawServer](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawserver)
, [RawRequest](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawrequest)
, [RawReply](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#rawreply)
, [Logger](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#logger)
\>(instance: [FastifyInstance](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyinstance)
, done: (err?: [FastifyError](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyfastifyerror)
) => void): Promise | void[](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#fastifyonclosehookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void "Direct link to fastifyonclosehookhandler-rawserver-rawrequest-rawreply-loggerinstance-fastifyinstance-done-err-fastifyerror--void-promiseunknown--void")
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L206)
Triggered when fastify.close() is invoked to stop the server. It is useful when plugins need a "shutdown" event, for example to close an open connection to a database.
* [TypeScript](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#typescript)
* [Learn By Example](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#learn-by-example)
* [Getting Started](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#getting-started)
* [Using Generics](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#using-generics)
* [JSON Schema](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#json-schema)
* [Plugins](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#plugins)
* [Code Completion In Vanilla JavaScript](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#code-completion-in-vanilla-javascript)
* [API Type System Documentation](https://fastify.dev/docs/v5.3.x/Reference/TypeScript/#api-type-system-documentation)
---
# Warnings | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Warnings/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
**Table of contents**
* [Warnings](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings)
* [Warnings In Fastify](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings-in-fastify)
* [Fastify Warning Codes](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-warning-codes)
* [FSTWRN001](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#FSTWRN001)
* [FSTWRN002](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#FSTWRN002)
* [Fastify Deprecation Codes](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-deprecation-codes)
Warnings[](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings "Direct link to Warnings")
----------------------------------------------------------------------------------------------------
### Warnings In Fastify[](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings-in-fastify "Direct link to Warnings In Fastify")
Fastify uses Node.js's [warning event](https://nodejs.org/api/process.html#event-warning)
API to notify users of deprecated features and coding mistakes. Fastify's warnings are recognizable by the `FSTWRN` and `FSTDEP` prefixes. When encountering such a warning, it is highly recommended to determine the cause using the [`--trace-warnings`](https://nodejs.org/api/cli.html#--trace-warnings)
and [`--trace-deprecation`](https://nodejs.org/api/cli.html#--trace-deprecation)
flags. These produce stack traces pointing to where the issue occurs in the application's code. Issues opened about warnings without this information will be closed due to lack of details.
Warnings can also be disabled, though it is not recommended. If necessary, use one of the following methods:
* Set the `NODE_NO_WARNINGS` environment variable to `1`
* Pass the `--no-warnings` flag to the node process
* Set `no-warnings` in the `NODE_OPTIONS` environment variable
For more information on disabling warnings, see [Node's documentation](https://nodejs.org/api/cli.html)
.
Disabling warnings may cause issues when upgrading Fastify versions. Only experienced users should consider disabling warnings.
### Fastify Warning Codes[](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-warning-codes "Direct link to Fastify Warning Codes")
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
| FSTWRN001 | The specified schema for a route is missing. This may indicate the schema is not well specified. | Check the schema for the route. | [#4647](https://github.com/fastify/fastify/pull/4647) |
| FSTWRN002 | The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`. | Do not mix async and callback style. | [#5139](https://github.com/fastify/fastify/pull/5139) |
### Fastify Deprecation Codes[](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-deprecation-codes "Direct link to Fastify Deprecation Codes")
Deprecation codes are supported by the Node.js CLI options:
* [\--no-deprecation](https://nodejs.org/api/cli.html#--no-deprecation)
* [\--throw-deprecation](https://nodejs.org/api/cli.html#--throw-deprecation)
* [\--trace-deprecation](https://nodejs.org/api/cli.html#--trace-deprecation)
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
* [Warnings](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings)
* [Warnings In Fastify](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#warnings-in-fastify)
* [Fastify Warning Codes](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-warning-codes)
* [Fastify Deprecation Codes](https://fastify.dev/docs/v5.3.x/Reference/Warnings/#fastify-deprecation-codes)
---
# Validation-and-Serialization | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Validation-and-Serialization/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Validation and Serialization[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validation-and-serialization "Direct link to Validation and Serialization")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify uses a schema-based approach. We recommend using [JSON Schema](https://json-schema.org/)
to validate routes and serialize outputs. Fastify compiles the schema into a highly performant function.
Validation is only attempted if the content type is `application/json`.
All examples use the [JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7)
specification.
> ⚠ Warning: Treat schema definitions as application code. Validation and serialization features use `new Function()`, which is unsafe with user-provided schemas. See [Ajv](https://npm.im/ajv)
> and [fast-json-stringify](https://npm.im/fast-json-stringify)
> for details.
>
> Whilst Fastify supports the [`$async` Ajv feature](https://ajv.js.org/guide/async-validation.html)
> , it should not be used for initial validation. Accessing databases during validation may lead to Denial of Service attacks. Use [Fastify's hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/)
> like `preHandler` for `async` tasks after validation.
### Core concepts[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#core-concepts "Direct link to Core concepts")
Validation and serialization are handled by two customizable dependencies:
* [Ajv v8](https://www.npmjs.com/package/ajv)
for request validation
* [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
for response body serialization
These dependencies share only the JSON schemas added to Fastify's instance via `.addSchema(schema)`.
#### Adding a shared schema[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#adding-a-shared-schema "Direct link to Adding a shared schema")
The `addSchema` API allows adding multiple schemas to the Fastify instance for reuse throughout the application. This API is encapsulated.
Shared schemas can be reused with the JSON Schema [**`$ref`**](https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8)
keyword. Here is an overview of how references work:
* `myField: { $ref: '#foo' }` searches for `$id: '#foo'` in the current schema
* `myField: { $ref: '#/definitions/foo' }` searches for `definitions.foo` in the current schema
* `myField: { $ref: 'http://url.com/sh.json#' }` searches for a shared schema with `$id: 'http://url.com/sh.json'`
* `myField: { $ref: 'http://url.com/sh.json#/definitions/foo' }` searches for a shared schema with `$id: 'http://url.com/sh.json'` and uses `definitions.foo`
* `myField: { $ref: 'http://url.com/sh.json#foo' }` searches for a shared schema with `$id: 'http://url.com/sh.json'` and looks for `$id: '#foo'` within it
**Simple usage:**
fastify.addSchema({ $id: 'http://example.com/', type: 'object', properties: { hello: { type: 'string' } }})fastify.post('/', { handler () {}, schema: { body: { type: 'array', items: { $ref: 'http://example.com#/properties/hello' } } }})
**`$ref` as root reference:**
fastify.addSchema({ $id: 'commonSchema', type: 'object', properties: { hello: { type: 'string' } }})fastify.post('/', { handler () {}, schema: { body: { $ref: 'commonSchema#' }, headers: { $ref: 'commonSchema#' } }})
#### Retrieving the shared schemas[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#retrieving-the-shared-schemas "Direct link to Retrieving the shared schemas")
If the validator and serializer are customized, `.addSchema` is not useful since Fastify no longer controls them. To access schemas added to the Fastify instance, use `.getSchemas()`:
fastify.addSchema({ $id: 'schemaId', type: 'object', properties: { hello: { type: 'string' } }})const mySchemas = fastify.getSchemas()const mySchema = fastify.getSchema('schemaId')
The `getSchemas` function is encapsulated and returns shared schemas available in the selected scope:
fastify.addSchema({ $id: 'one', my: 'hello' })// will return only `one` schemafastify.get('/', (request, reply) => { reply.send(fastify.getSchemas()) })fastify.register((instance, opts, done) => { instance.addSchema({ $id: 'two', my: 'ciao' }) // will return `one` and `two` schemas instance.get('/sub', (request, reply) => { reply.send(instance.getSchemas()) }) instance.register((subinstance, opts, done) => { subinstance.addSchema({ $id: 'three', my: 'hola' }) // will return `one`, `two` and `three` subinstance.get('/deep', (request, reply) => { reply.send(subinstance.getSchemas()) }) done() }) done()})
### Validation[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validation "Direct link to Validation")
Route validation relies on [Ajv v8](https://www.npmjs.com/package/ajv)
, a high-performance JSON Schema validator. To validate input, add the required fields to the route schema.
Supported validations include:
* `body`: validates the request body for POST, PUT, or PATCH methods.
* `querystring` or `query`: validates the query string.
* `params`: validates the route parameters.
* `headers`: validates the request headers.
Validations can be a complete JSON Schema object with a `type` of `'object'` and a `'properties'` object containing parameters, or a simpler variation listing parameters at the top level.
> ℹ For using the latest Ajv (v8), refer to the [`schemaController`](https://fastify.dev/docs/v5.3.x/Reference/Server/#schema-controller)
> section.
Example:
const bodyJsonSchema = { type: 'object', required: ['requiredKey'], properties: { someKey: { type: 'string' }, someOtherKey: { type: 'number' }, requiredKey: { type: 'array', maxItems: 3, items: { type: 'integer' } }, nullableKey: { type: ['number', 'null'] }, // or { type: 'number', nullable: true } multipleTypesKey: { type: ['boolean', 'number'] }, multipleRestrictedTypesKey: { oneOf: [ { type: 'string', maxLength: 5 }, { type: 'number', minimum: 10 } ] }, enumKey: { type: 'string', enum: ['John', 'Foo'] }, notTypeKey: { not: { type: 'array' } } }}const queryStringJsonSchema = { type: 'object', properties: { name: { type: 'string' }, excitement: { type: 'integer' } }}const paramsJsonSchema = { type: 'object', properties: { par1: { type: 'string' }, par2: { type: 'number' } }}const headersJsonSchema = { type: 'object', properties: { 'x-foo': { type: 'string' } }, required: ['x-foo']}const schema = { body: bodyJsonSchema, querystring: queryStringJsonSchema, params: paramsJsonSchema, headers: headersJsonSchema}fastify.post('/the/url', { schema }, handler)
For `body` schema, it is further possible to differentiate the schema per content type by nesting the schemas inside `content` property. The schema validation will be applied based on the `Content-Type` header in the request.
fastify.post('/the/url', { schema: { body: { content: { 'application/json': { schema: { type: 'object' } }, 'text/plain': { schema: { type: 'string' } } // Other content types will not be validated } } }}, handler)
Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html)
values to the types specified in the schema `type` keywords, both to pass validation and to use the correctly typed data afterwards.
The Ajv default configuration in Fastify supports coercing array parameters in `querystring`. Example:
const opts = { schema: { querystring: { type: 'object', properties: { ids: { type: 'array', default: [] }, }, } }}fastify.get('/', opts, (request, reply) => { reply.send({ params: request.query }) // echo the querystring})fastify.listen({ port: 3000 }, (err) => { if (err) throw err})
curl -X GET "http://localhost:3000/?ids=1{"params":{"ids":["1"]}}
A custom schema validator can be specified for each parameter type (body, querystring, params, headers).
For example, the following code disables type coercion only for the `body` parameters, changing the Ajv default options:
const schemaCompilers = { body: new Ajv({ removeAdditional: false, coerceTypes: false, allErrors: true }), params: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true }), querystring: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true }), headers: new Ajv({ removeAdditional: false, coerceTypes: true, allErrors: true })}server.setValidatorCompiler(req => { if (!req.httpPart) { throw new Error('Missing httpPart') } const compiler = schemaCompilers[req.httpPart] if (!compiler) { throw new Error(`Missing compiler for ${req.httpPart}`) } return compiler.compile(req.schema)})
For more information, see [Ajv Coercion](https://ajv.js.org/coercion.html)
.
#### Ajv Plugins[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#ajv-plugins "Direct link to Ajv Plugins")
A list of plugins can be provided for use with the default `ajv` instance. Ensure the plugin is **compatible with the Ajv version shipped within Fastify**.
> Refer to [`ajv options`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ajv)
> to check plugins format.
const fastify = require('fastify')({ ajv: { plugins: [ require('ajv-merge-patch') ] }})fastify.post('/', { handler (req, reply) { reply.send({ ok: 1 }) }, schema: { body: { $patch: { source: { type: 'object', properties: { q: { type: 'string' } } }, with: [ { op: 'add', path: '/properties/q', value: { type: 'number' } } ] } } }})fastify.post('/foo', { handler (req, reply) { reply.send({ ok: 1 }) }, schema: { body: { $merge: { source: { type: 'object', properties: { q: { type: 'string' } } }, with: { required: ['q'] } } } }})
#### Validator Compiler[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validator-compiler "Direct link to Validator Compiler")
The `validatorCompiler` is a function that returns a function to validate the body, URL parameters, headers, and query string. The default `validatorCompiler` returns a function that implements the [ajv](https://ajv.js.org/)
validation interface. Fastify uses it internally to speed up validation.
Fastify's [baseline ajv configuration](https://github.com/fastify/ajv-compiler#ajv-configuration)
is:
{ coerceTypes: 'array', // change data type of data to match type keyword useDefaults: true, // replace missing properties and items with the values from corresponding default keyword removeAdditional: true, // remove additional properties if additionalProperties is set to false, see: https://ajv.js.org/guide/modifying-data.html#removing-additional-properties uriResolver: require('fast-uri'), addUsedSchema: false, // Explicitly set allErrors to `false`. // When set to `true`, a DoS attack is possible. allErrors: false}
Modify the baseline configuration by providing [`ajv.customOptions`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-ajv)
to the Fastify factory.
To change or set additional config options, create a custom instance and override the existing one:
const fastify = require('fastify')()const Ajv = require('ajv')const ajv = new Ajv({ removeAdditional: 'all', useDefaults: true, coerceTypes: 'array', // any other options // ...})fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => { return ajv.compile(schema)})
> 🛈 Note: When using a custom validator instance, add schemas to the validator instead of Fastify. Fastify's `addSchema` method will not recognize the custom validator.
##### Using other validation libraries[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#using-other-validation-libraries "Direct link to Using other validation libraries")
The `setValidatorCompiler` function allows substituting `ajv` with other JavaScript validation libraries like [joi](https://github.com/hapijs/joi/)
or [yup](https://github.com/jquense/yup/)
, or a custom one:
const Joi = require('joi')fastify.post('/the/url', { schema: { body: Joi.object().keys({ hello: Joi.string().required() }).required() }, validatorCompiler: ({ schema, method, url, httpPart }) => { return data => schema.validate(data) }}, handler)
const yup = require('yup')// Validation options to match ajv's baseline options used in Fastifyconst yupOptions = { strict: false, abortEarly: false, // return all errors stripUnknown: true, // remove additional properties recursive: true}fastify.post('/the/url', { schema: { body: yup.object({ age: yup.number().integer().required(), sub: yup.object().shape({ name: yup.string().required() }).required() }) }, validatorCompiler: ({ schema, method, url, httpPart }) => { return function (data) { // with option strict = false, yup `validateSync` function returns the // coerced value if validation was successful, or throws if validation failed try { const result = schema.validateSync(data, yupOptions) return { value: result } } catch (e) { return { error: e } } } }}, handler)
##### .statusCode property[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#statuscode-property "Direct link to .statusCode property")
All validation errors have a `.statusCode` property set to `400`, ensuring the default error handler sets the response status code to `400`.
fastify.setErrorHandler(function (error, request, reply) { request.log.error(error, `This error has status code ${error.statusCode}`) reply.status(error.statusCode).send(error)})
##### Validation messages with other validation libraries[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validation-messages-with-other-validation-libraries "Direct link to Validation messages with other validation libraries")
Fastify's validation error messages are tightly coupled to the default validation engine: errors returned from `ajv` are eventually run through the `schemaErrorFormatter` function which builds human-friendly error messages. However, the `schemaErrorFormatter` function is written with `ajv` in mind. This may result in odd or incomplete error messages when using other validation libraries.
To circumvent this issue, there are two main options:
1. Ensure the validation function (returned by the custom `schemaCompiler`) returns errors in the same structure and format as `ajv`.
2. Use a custom `errorHandler` to intercept and format custom validation errors.
Fastify adds two properties to all validation errors to help write a custom `errorHandler`:
* `validation`: the content of the `error` property of the object returned by the validation function (returned by the custom `schemaCompiler`)
* `validationContext`: the context (body, params, query, headers) where the validation error occurred
A contrived example of such a custom `errorHandler` handling validation errors is shown below:
const errorHandler = (error, request, reply) => { const statusCode = error.statusCode let response const { validation, validationContext } = error // check if we have a validation error if (validation) { response = { // validationContext will be 'body', 'params', 'headers', or 'query' message: `A validation error occurred when validating the ${validationContext}...`, // this is the result of the validation library... errors: validation } } else { response = { message: 'An error occurred...' } } // any additional work here, eg. log error // ... reply.status(statusCode).send(response)}
### Serialization[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#serialization "Direct link to Serialization")
Fastify uses [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
to send data as JSON if an output schema is provided in the route options. Using an output schema can drastically increase throughput and help prevent accidental disclosure of sensitive information.
Example:
const schema = { response: { 200: { type: 'object', properties: { value: { type: 'string' }, otherValue: { type: 'boolean' } } } }}fastify.post('/the/url', { schema }, handler)
The response schema is based on the status code. To use the same schema for multiple status codes, use `'2xx'` or `default`, for example:
const schema = { response: { default: { type: 'object', properties: { error: { type: 'boolean', default: true } } }, '2xx': { type: 'object', properties: { value: { type: 'string' }, otherValue: { type: 'boolean' } } }, 201: { // the contract syntax value: { type: 'string' } } }}fastify.post('/the/url', { schema }, handler)
A specific response schema can be defined for different content types. For example:
const schema = { response: { 200: { description: 'Response schema that support different content types' content: { 'application/json': { schema: { name: { type: 'string' }, image: { type: 'string' }, address: { type: 'string' } } }, 'application/vnd.v1+json': { schema: { type: 'array', items: { $ref: 'test' } } } } }, '3xx': { content: { 'application/vnd.v2+json': { schema: { fullName: { type: 'string' }, phone: { type: 'string' } } } } }, default: { content: { // */* is match-all content-type '*/*': { schema: { desc: { type: 'string' } } } } } }}fastify.post('/url', { schema }, handler)
#### Serializer Compiler[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#serializer-compiler "Direct link to Serializer Compiler")
The `serializerCompiler` returns a function that must return a string from an input object. When defining a response JSON Schema, change the default serialization method by providing a function to serialize each route.
fastify.setSerializerCompiler(({ schema, method, url, httpStatus, contentType }) => { return data => JSON.stringify(data)})fastify.get('/user', { handler (req, reply) { reply.send({ id: 1, name: 'Foo', image: 'BIG IMAGE' }) }, schema: { response: { '2xx': { type: 'object', properties: { id: { type: 'number' }, name: { type: 'string' } } } } }})
_To set a custom serializer in a specific part of the code, use [`reply.serializer(...)`](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializerfunc)
._
### Error Handling[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#error-handling "Direct link to Error Handling")
When schema validation fails for a request, Fastify will automatically return a status 400 response including the result from the validator in the payload. For example, if the following schema is used for a route:
const schema = { body: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }}
If the request fails to satisfy the schema, the route will return a response with the following payload:
{ "statusCode": 400, "error": "Bad Request", "message": "body should have required property 'name'"}
To handle errors inside the route, specify the `attachValidation` option. If there is a validation error, the `validationError` property of the request will contain the `Error` object with the raw validation result as shown below:
const fastify = Fastify()fastify.post('/', { schema, attachValidation: true }, function (req, reply) { if (req.validationError) { // `req.validationError.validation` contains the raw validation error reply.code(400).send(req.validationError) }})
#### `schemaErrorFormatter`[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schemaerrorformatter "Direct link to schemaerrorformatter")
To format errors, provide a sync function that returns an error as the `schemaErrorFormatter` option when instantiating Fastify. The context function will be the Fastify server instance.
`errors` is an array of Fastify schema errors `FastifySchemaValidationError`. `dataVar` is the currently validated part of the schema (params, body, querystring, headers).
const fastify = Fastify({ schemaErrorFormatter: (errors, dataVar) => { // ... my formatting logic return new Error(myErrorMessage) }})// orfastify.setSchemaErrorFormatter(function (errors, dataVar) { this.log.error({ err: errors }, 'Validation failed') // ... my formatting logic return new Error(myErrorMessage)})
Use [setErrorHandler](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
to define a custom response for validation errors such as:
fastify.setErrorHandler(function (error, request, reply) { if (error.validation) { reply.status(422).send(new Error('validation failed')) }})
For custom error responses in the schema, see [`ajv-errors`](https://github.com/epoberezkin/ajv-errors)
. Check out the [example](https://github.com/fastify/example/blob/HEAD/validation-messages/custom-errors-messages.js)
usage.
> Install version 1.0.1 of `ajv-errors`, as later versions are not compatible with AJV v6 (the version shipped by Fastify v3).
Below is an example showing how to add **custom error messages for each property** of a schema by supplying custom AJV options. Inline comments in the schema describe how to configure it to show a different error message for each case:
const fastify = Fastify({ ajv: { customOptions: { jsonPointers: true, // ⚠ Warning: Enabling this option may lead to this security issue https://www.cvedetails.com/cve/CVE-2020-8192/ allErrors: true }, plugins: [ require('ajv-errors') ] }})const schema = { body: { type: 'object', properties: { name: { type: 'string', errorMessage: { type: 'Bad name' } }, age: { type: 'number', errorMessage: { type: 'Bad age', // specify custom message for min: 'Too young' // all constraints except required } } }, required: ['name', 'age'], errorMessage: { required: { name: 'Why no name!', // specify error message for when the age: 'Why no age!' // property is missing from input } } }}fastify.post('/', { schema, }, (request, reply) => { reply.send({ hello: 'world' })})
To return localized error messages, see [ajv-i18n](https://github.com/epoberezkin/ajv-i18n)
.
const localize = require('ajv-i18n')const fastify = Fastify()const schema = { body: { type: 'object', properties: { name: { type: 'string', }, age: { type: 'number', } }, required: ['name', 'age'], }}fastify.setErrorHandler(function (error, request, reply) { if (error.validation) { localize.ru(error.validation) reply.status(400).send(error.validation) return } reply.send(error)})
### JSON Schema support[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#json-schema-support "Direct link to JSON Schema support")
JSON Schema provides utilities to optimize schemas. Combined with Fastify's shared schema, all schemas can be easily reused.
| Use Case | Validator | Serializer |
| --- | --- | --- |
| `$ref` to `$id` | ️️✔️ | ✔️ |
| `$ref` to `/definitions` | ✔️ | ✔️ |
| `$ref` to shared schema `$id` | ✔️ | ✔️ |
| `$ref` to shared schema `/definitions` | ✔️ | ✔️ |
#### Examples[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#examples "Direct link to Examples")
##### Usage of `$ref` to `$id` in same JSON Schema[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#usage-of-ref-to-id-in-same-json-schema "Direct link to usage-of-ref-to-id-in-same-json-schema")
const refToId = { type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }, properties: { home: { $ref: '#address' }, work: { $ref: '#address' } }}
##### Usage of `$ref` to `/definitions` in same JSON Schema[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#usage-of-ref-to-definitions-in-same-json-schema "Direct link to usage-of-ref-to-definitions-in-same-json-schema")
const refToDefinitions = { type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }, properties: { home: { $ref: '#/definitions/foo' }, work: { $ref: '#/definitions/foo' } }}
##### Usage `$ref` to a shared schema `$id` as external schema[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#usage-ref-to-a-shared-schema-id-as-external-schema "Direct link to usage-ref-to-a-shared-schema-id-as-external-schema")
fastify.addSchema({ $id: 'http://foo/common.json', type: 'object', definitions: { foo: { $id: '#address', type: 'object', properties: { city: { type: 'string' } } } }})const refToSharedSchemaId = { type: 'object', properties: { home: { $ref: 'http://foo/common.json#address' }, work: { $ref: 'http://foo/common.json#address' } }}
##### Usage `$ref` to a shared schema `/definitions` as external schema[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#usage-ref-to-a-shared-schema-definitions-as-external-schema "Direct link to usage-ref-to-a-shared-schema-definitions-as-external-schema")
fastify.addSchema({ $id: 'http://foo/shared.json', type: 'object', definitions: { foo: { type: 'object', properties: { city: { type: 'string' } } } }})const refToSharedSchemaDefinitions = { type: 'object', properties: { home: { $ref: 'http://foo/shared.json#/definitions/foo' }, work: { $ref: 'http://foo/shared.json#/definitions/foo' } }}
### Resources[](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#resources "Direct link to Resources")
* [JSON Schema](https://json-schema.org/)
* [Understanding JSON Schema](https://spacetelescope.github.io/understanding-json-schema/)
* [fast-json-stringify documentation](https://github.com/fastify/fast-json-stringify)
* [Ajv documentation](https://github.com/epoberezkin/ajv/blob/master/README.md)
* [Ajv i18n](https://github.com/epoberezkin/ajv-i18n)
* [Ajv custom errors](https://github.com/epoberezkin/ajv-errors)
* Custom error handling with core methods with error file dumping [example](https://github.com/fastify/example/tree/main/validation-messages)
* [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validation-and-serialization)
* [Core concepts](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#core-concepts)
* [Validation](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#validation)
* [Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#serialization)
* [Error Handling](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#error-handling)
* [JSON Schema support](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#json-schema-support)
* [Resources](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#resources)
---
# Server | Fastify
[Skip to main content](https://fastify.dev/docs/v5.3.x/Reference/Server/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Server/)
** (latest (v5.4.x)).
Version: v5.3.x
On this page
Factory[](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory "Direct link to Factory")
-----------------------------------------------------------------------------------------------
The Fastify module exports a factory function that is used to create new `**Fastify server**` instances. This factory function accepts an options object which is used to customize the resulting instance. This document describes the properties available in that options object.
* [Factory](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory)
* [`http`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http)
* [`http2`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2)
* [`https`](https://fastify.dev/docs/v5.3.x/Reference/Server/#https)
* [`connectionTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#connectiontimeout)
* [`keepAliveTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#keepalivetimeout)
* [`forceCloseConnections`](https://fastify.dev/docs/v5.3.x/Reference/Server/#forcecloseconnections)
* [`maxRequestsPerSocket`](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxrequestspersocket)
* [`requestTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requesttimeout)
* [`ignoreTrailingSlash`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoretrailingslash)
* [`ignoreDuplicateSlashes`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoreduplicateslashes)
* [`maxParamLength`](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxparamlength)
* [`bodyLimit`](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit)
* [`onProtoPoisoning`](https://fastify.dev/docs/v5.3.x/Reference/Server/#onprotopoisoning)
* [`onConstructorPoisoning`](https://fastify.dev/docs/v5.3.x/Reference/Server/#onconstructorpoisoning)
* [`logger`](https://fastify.dev/docs/v5.3.x/Reference/Server/#logger)
* [`loggerInstance`](https://fastify.dev/docs/v5.3.x/Reference/Server/#loggerInstance)
* [`disableRequestLogging`](https://fastify.dev/docs/v5.3.x/Reference/Server/#disablerequestlogging)
* [`serverFactory`](https://fastify.dev/docs/v5.3.x/Reference/Server/#serverfactory)
* [`caseSensitive`](https://fastify.dev/docs/v5.3.x/Reference/Server/#casesensitive)
* [`allowUnsafeRegex`](https://fastify.dev/docs/v5.3.x/Reference/Server/#allowunsaferegex)
* [`requestIdHeader`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidheader)
* [`requestIdLogLabel`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidloglabel)
* [`genReqId`](https://fastify.dev/docs/v5.3.x/Reference/Server/#genreqid)
* [`trustProxy`](https://fastify.dev/docs/v5.3.x/Reference/Server/#trustproxy)
* [`pluginTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#plugintimeout)
* [`querystringParser`](https://fastify.dev/docs/v5.3.x/Reference/Server/#querystringparser)
* [`exposeHeadRoutes`](https://fastify.dev/docs/v5.3.x/Reference/Server/#exposeheadroutes)
* [`constraints`](https://fastify.dev/docs/v5.3.x/Reference/Server/#constraints)
* [`return503OnClosing`](https://fastify.dev/docs/v5.3.x/Reference/Server/#return503onclosing)
* [`ajv`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ajv)
* [`serializerOpts`](https://fastify.dev/docs/v5.3.x/Reference/Server/#serializeropts)
* [`http2SessionTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2sessiontimeout)
* [`frameworkErrors`](https://fastify.dev/docs/v5.3.x/Reference/Server/#frameworkerrors)
* [`clientErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#clienterrorhandler)
* [`rewriteUrl`](https://fastify.dev/docs/v5.3.x/Reference/Server/#rewriteurl)
* [`useSemicolonDelimiter`](https://fastify.dev/docs/v5.3.x/Reference/Server/#usesemicolondelimiter)
* [Instance](https://fastify.dev/docs/v5.3.x/Reference/Server/#instance)
* [Server Methods](https://fastify.dev/docs/v5.3.x/Reference/Server/#server-methods)
* [server](https://fastify.dev/docs/v5.3.x/Reference/Server/#server)
* [after](https://fastify.dev/docs/v5.3.x/Reference/Server/#after)
* [ready](https://fastify.dev/docs/v5.3.x/Reference/Server/#ready)
* [listen](https://fastify.dev/docs/v5.3.x/Reference/Server/#listen)
* [`listenTextResolver`](https://fastify.dev/docs/v5.3.x/Reference/Server/#listentextresolver)
* [addresses](https://fastify.dev/docs/v5.3.x/Reference/Server/#addresses)
* [routing](https://fastify.dev/docs/v5.3.x/Reference/Server/#routing)
* [route](https://fastify.dev/docs/v5.3.x/Reference/Server/#route)
* [hasRoute](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasroute)
* [findRoute](https://fastify.dev/docs/v5.3.x/Reference/Server/#findroute)
* [close](https://fastify.dev/docs/v5.3.x/Reference/Server/#close)
* [decorate\*](https://fastify.dev/docs/v5.3.x/Reference/Server/#decorate)
* [register](https://fastify.dev/docs/v5.3.x/Reference/Server/#register)
* [addHook](https://fastify.dev/docs/v5.3.x/Reference/Server/#addhook)
* [prefix](https://fastify.dev/docs/v5.3.x/Reference/Server/#prefix)
* [pluginName](https://fastify.dev/docs/v5.3.x/Reference/Server/#pluginname)
* [hasPlugin](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasplugin)
* [listeningOrigin](https://fastify.dev/docs/v5.3.x/Reference/Server/#listeningorigin)
* [log](https://fastify.dev/docs/v5.3.x/Reference/Server/#log)
* [version](https://fastify.dev/docs/v5.3.x/Reference/Server/#version)
* [inject](https://fastify.dev/docs/v5.3.x/Reference/Server/#inject)
* [addHttpMethod](https://fastify.dev/docs/v5.3.x/Reference/Server/#addHttpMethod)
* [addSchema](https://fastify.dev/docs/v5.3.x/Reference/Server/#addschema)
* [getSchemas](https://fastify.dev/docs/v5.3.x/Reference/Server/#getschemas)
* [getSchema](https://fastify.dev/docs/v5.3.x/Reference/Server/#getschema)
* [setReplySerializer](https://fastify.dev/docs/v5.3.x/Reference/Server/#setreplyserializer)
* [setValidatorCompiler](https://fastify.dev/docs/v5.3.x/Reference/Server/#setvalidatorcompiler)
* [setSchemaErrorFormatter](https://fastify.dev/docs/v5.3.x/Reference/Server/#setschemaerrorformatter)
* [setSerializerCompiler](https://fastify.dev/docs/v5.3.x/Reference/Server/#setserializercompiler)
* [validatorCompiler](https://fastify.dev/docs/v5.3.x/Reference/Server/#validatorcompiler)
* [serializerCompiler](https://fastify.dev/docs/v5.3.x/Reference/Server/#serializercompiler)
* [schemaErrorFormatter](https://fastify.dev/docs/v5.3.x/Reference/Server/#schemaerrorformatter)
* [schemaController](https://fastify.dev/docs/v5.3.x/Reference/Server/#schemacontroller)
* [setNotFoundHandler](https://fastify.dev/docs/v5.3.x/Reference/Server/#setnotfoundhandler)
* [setErrorHandler](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
* [setChildLoggerFactory](https://fastify.dev/docs/v5.3.x/Reference/Server/#setchildloggerfactory)
* [setGenReqId](https://fastify.dev/docs/v5.3.x/Reference/Server/#setGenReqId)
* [addConstraintStrategy](https://fastify.dev/docs/v5.3.x/Reference/Server/#addconstraintstrategy)
* [hasConstraintStrategy](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasconstraintstrategy)
* [printRoutes](https://fastify.dev/docs/v5.3.x/Reference/Server/#printroutes)
* [printPlugins](https://fastify.dev/docs/v5.3.x/Reference/Server/#printplugins)
* [addContentTypeParser](https://fastify.dev/docs/v5.3.x/Reference/Server/#addcontenttypeparser)
* [hasContentTypeParser](https://fastify.dev/docs/v5.3.x/Reference/Server/#hascontenttypeparser)
* [removeContentTypeParser](https://fastify.dev/docs/v5.3.x/Reference/Server/#removecontenttypeparser)
* [removeAllContentTypeParsers](https://fastify.dev/docs/v5.3.x/Reference/Server/#removeallcontenttypeparsers)
* [getDefaultJsonParser](https://fastify.dev/docs/v5.3.x/Reference/Server/#getdefaultjsonparser)
* [defaultTextParser](https://fastify.dev/docs/v5.3.x/Reference/Server/#defaulttextparser)
* [errorHandler](https://fastify.dev/docs/v5.3.x/Reference/Server/#errorhandler)
* [childLoggerFactory](https://fastify.dev/docs/v5.3.x/Reference/Server/#childloggerfactory)
* [Symbol.asyncDispose](https://fastify.dev/docs/v5.3.x/Reference/Server/#symbolasyncdispose)
* [initialConfig](https://fastify.dev/docs/v5.3.x/Reference/Server/#initialconfig)
### `http`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#http "Direct link to http")
* Default: `null`
An object used to configure the server's listening socket. The options are the same as the Node.js core [`createServer` method](https://nodejs.org/docs/latest-v20.x/api/http.html#httpcreateserveroptions-requestlistener)
.
This option is ignored if options [`http2`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-http2)
or [`https`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-https)
are set.
### `http2`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2 "Direct link to http2")
* Default: `false`
If `true` Node.js core's [HTTP/2](https://nodejs.org/dist/latest-v20.x/docs/api/http2.html)
module is used for binding the socket.
### `https`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#https "Direct link to https")
* Default: `null`
An object used to configure the server's listening socket for TLS. The options are the same as the Node.js core [`createServer` method](https://nodejs.org/dist/latest-v20.x/docs/api/https.html#https_https_createserver_options_requestlistener)
. When this property is `null`, the socket will not be configured for TLS.
This option also applies when the [`http2`](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-http2)
option is set.
### `connectionTimeout`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#connectiontimeout "Direct link to connectiontimeout")
* Default: `0` (no timeout)
Defines the server timeout in milliseconds. See documentation for [`server.timeout` property](https://nodejs.org/api/http.html#http_server_timeout)
to understand the effect of this option.
When `serverFactory` option is specified this option is ignored.
### `keepAliveTimeout`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#keepalivetimeout "Direct link to keepalivetimeout")
* Default: `72000` (72 seconds)
Defines the server keep-alive timeout in milliseconds. See documentation for [`server.keepAliveTimeout` property](https://nodejs.org/api/http.html#http_server_keepalivetimeout)
to understand the effect of this option. This option only applies when HTTP/1 is in use.
When `serverFactory` option is specified this option is ignored.
### `forceCloseConnections`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#forcecloseconnections "Direct link to forcecloseconnections")
* Default: `"idle"` if the HTTP server allows it, `false` otherwise
When set to `true`, upon [`close`](https://fastify.dev/docs/v5.3.x/Reference/Server/#close)
the server will iterate the current persistent connections and [destroy their sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror)
.
> ⚠ Warning: Connections are not inspected to determine if requests have been completed.
Fastify will prefer the HTTP server's [`closeAllConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseallconnections)
method if supported, otherwise, it will use internal connection tracking.
When set to `"idle"`, upon [`close`](https://fastify.dev/docs/v5.3.x/Reference/Server/#close)
the server will iterate the current persistent connections which are not sending a request or waiting for a response and destroy their sockets. The value is only supported if the HTTP server supports the [`closeIdleConnections`](https://nodejs.org/dist/latest-v18.x/docs/api/http.html#servercloseidleconnections)
method, otherwise attempting to set it will throw an exception.
### `maxRequestsPerSocket`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxrequestspersocket "Direct link to maxrequestspersocket")
* Default: `0` (no limit)
Defines the maximum number of requests a socket can handle before closing keep alive connection. See [`server.maxRequestsPerSocket` property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_maxrequestspersocket)
to understand the effect of this option. This option only applies when HTTP/1.1 is in use. Also, when `serverFactory` option is specified, this option is ignored.
> 🛈 Note: At the time of writing, only node >= v16.10.0 supports this option.
### `requestTimeout`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#requesttimeout "Direct link to requesttimeout")
* Default: `0` (no limit)
Defines the maximum number of milliseconds for receiving the entire request from the client. See [`server.requestTimeout` property](https://nodejs.org/dist/latest/docs/api/http.html#http_server_requesttimeout)
to understand the effect of this option.
When `serverFactory` option is specified, this option is ignored. It must be set to a non-zero value (e.g. 120 seconds) to protect against potential Denial-of-Service attacks in case the server is deployed without a reverse proxy in front.
> 🛈 Note: At the time of writing, only node >= v14.11.0 supports this option
### `ignoreTrailingSlash`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoretrailingslash "Direct link to ignoretrailingslash")
* Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
to handle routing. By default, Fastify will take into account the trailing slashes. Paths like `/foo` and `/foo/` are treated as different paths. If you want to change this, set this flag to `true`. That way, both `/foo` and `/foo/` will point to the same route. This option applies to _all_ route registrations for the resulting server instance.
const fastify = require('fastify')({ ignoreTrailingSlash: true})// registers both "/foo" and "/foo/"fastify.get('/foo/', function (req, reply) { reply.send('foo')})// registers both "/bar" and "/bar/"fastify.get('/bar', function (req, reply) { reply.send('bar')})
### `ignoreDuplicateSlashes`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoreduplicateslashes "Direct link to ignoreduplicateslashes")
* Default: `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
to handle routing. You can use `ignoreDuplicateSlashes` option to remove duplicate slashes from the path. It removes duplicate slashes in the route path and the request URL. This option applies to _all_ route registrations for the resulting server instance.
When `ignoreTrailingSlash` and `ignoreDuplicateSlashes` are both set to `true` Fastify will remove duplicate slashes, and then trailing slashes, meaning `//a//b//c//` will be converted to `/a/b/c`.
const fastify = require('fastify')({ ignoreDuplicateSlashes: true})// registers "/foo/bar/"fastify.get('///foo//bar//', function (req, reply) { reply.send('foo')})
### `maxParamLength`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxparamlength "Direct link to maxparamlength")
* Default: `100`
You can set a custom length for parameters in parametric (standard, regex, and multi) routes by using `maxParamLength` option; the default value is 100 characters. If the maximum length limit is reached, the not found route will be invoked.
This can be useful especially if you have a regex-based route, protecting you against [ReDoS attacks](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS)
.
### `bodyLimit`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit "Direct link to bodylimit")
* Default: `1048576` (1MiB)
Defines the maximum payload, in bytes, the server is allowed to accept. The default body reader sends [`FST_ERR_CTP_BODY_TOO_LARGE`](https://fastify.dev/docs/v5.3.x/Reference/Errors/#fst_err_ctp_body_too_large)
reply, if the size of the body exceeds this limit. If [`preParsing` hook](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#preparsing)
is provided, this limit is applied to the size of the stream the hook returns (i.e. the size of "decoded" body).
### `onProtoPoisoning`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#onprotopoisoning "Direct link to onprotopoisoning")
* Default: `'error'`
Defines what action the framework must take when parsing a JSON object with `__proto__`. This functionality is provided by [secure-json-parse](https://github.com/fastify/secure-json-parse)
. See [Prototype Poisoning](https://fastify.dev/docs/v5.3.x/Guides/Prototype-Poisoning/)
for more details about prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `onConstructorPoisoning`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#onconstructorpoisoning "Direct link to onconstructorpoisoning")
* Default: `'error'`
Defines what action the framework must take when parsing a JSON object with `constructor`. This functionality is provided by [secure-json-parse](https://github.com/fastify/secure-json-parse)
. See [Prototype Poisoning](https://fastify.dev/docs/v5.3.x/Guides/Prototype-Poisoning/)
for more details about prototype poisoning attacks.
Possible values are `'error'`, `'remove'`, or `'ignore'`.
### `logger`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#logger "Direct link to logger")
Fastify includes built-in logging via the [Pino](https://getpino.io/)
logger. This property is used to configure the internal logger instance.
The possible values this property may have are:
* Default: `false`. The logger is disabled. All logging methods will point to a null logger [abstract-logging](https://npm.im/abstract-logging)
instance.
* `object`: a standard Pino [options object](https://github.com/pinojs/pino/blob/c77d8ec5ce/docs/API.md#constructor)
. This will be passed directly to the Pino constructor. If the following properties are not present on the object, they will be added accordingly:
* `level`: the minimum logging level. If not set, it will be set to `'info'`.
* `serializers`: a hash of serialization functions. By default, serializers are added for `req` (incoming request objects), `res` (outgoing response objects), and `err` (standard `Error` objects). When a log method receives an object with any of these properties then the respective serializer will be used for that property. For example:
fastify.get('/foo', function (req, res) { req.log.info({req}) // log the serialized request object res.send('foo')})
Any user-supplied serializer will override the default serializer of the corresponding property.
### `loggerInstance`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#loggerinstance "Direct link to loggerinstance")
* Default: `null`
A custom logger instance. The logger must be a Pino instance or conform to the Pino interface by having the following methods: `info`, `error`, `debug`, `fatal`, `warn`, `trace`, `child`. For example:
const pino = require('pino')();const customLogger = { info: function (o, ...n) {}, warn: function (o, ...n) {}, error: function (o, ...n) {}, fatal: function (o, ...n) {}, trace: function (o, ...n) {}, debug: function (o, ...n) {}, child: function() { const child = Object.create(this); child.pino = pino.child(...arguments); return child; },};const fastify = require('fastify')({logger: customLogger});
### `disableRequestLogging`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#disablerequestlogging "Direct link to disablerequestlogging")
* Default: `false`
When logging is enabled, Fastify will issue an `info` level log message when a request is received and when the response for that request has been sent. By setting this option to `true`, these log messages will be disabled. This allows for more flexible request start and end logging by attaching custom `onRequest` and `onResponse` hooks.
The other log entries that will be disabled are:
* an error log written by the default `onResponse` hook on reply callback errors
* the error and info logs written by the `defaultErrorHandler` on error management
* the info log written by the `fourOhFour` handler when a non existent route is requested
Other log messages emitted by Fastify will stay enabled, like deprecation warnings and messages emitted when requests are received while the server is closing.
// Examples of hooks to replicate the disabled functionality.fastify.addHook('onRequest', (req, reply, done) => { req.log.info({ url: req.raw.url, id: req.id }, 'received request') done()})fastify.addHook('onResponse', (req, reply, done) => { req.log.info({ url: req.raw.originalUrl, statusCode: reply.raw.statusCode }, 'request completed') done()})
### `serverFactory`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#serverfactory "Direct link to serverfactory")
You can pass a custom HTTP server to Fastify by using the `serverFactory` option.
`serverFactory` is a function that takes a `handler` parameter, which takes the `request` and `response` objects as parameters, and an options object, which is the same you have passed to Fastify.
const serverFactory = (handler, opts) => { const server = http.createServer((req, res) => { handler(req, res) }) return server}const fastify = Fastify({ serverFactory })fastify.get('/', (req, reply) => { reply.send({ hello: 'world' })})fastify.listen({ port: 3000 })
Internally Fastify uses the API of Node core HTTP server, so if you are using a custom server you must be sure to have the same API exposed. If not, you can enhance the server instance inside the `serverFactory` function before the `return` statement.
### `caseSensitive`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#casesensitive "Direct link to casesensitive")
* Default: `true`
When `true` routes are registered as case-sensitive. That is, `/foo` is not equal to `/Foo`. When `false` then routes are case-insensitive.
Please note that setting this option to `false` goes against [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1)
.
By setting `caseSensitive` to `false`, all paths will be matched as lowercase, but the route parameters or wildcards will maintain their original letter casing. This option does not affect query strings, please refer to [`querystringParser`](https://fastify.dev/docs/v5.3.x/Reference/Server/#querystringparser)
to change their handling.
fastify.get('/user/:username', (request, reply) => { // Given the URL: /USER/NodeJS console.log(request.params.username) // -> 'NodeJS'})
### `allowUnsafeRegex`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#allowunsaferegex "Direct link to allowunsaferegex")
* Default `false`
Disabled by default, so routes only allow safe regular expressions. To use unsafe expressions, set `allowUnsafeRegex` to `true`.
fastify.get('/user/:id(^([0-9]+){4}$)', (request, reply) => { // Throws an error without allowUnsafeRegex = true})
### `requestIdHeader`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidheader "Direct link to requestidheader")
* Default: `'request-id'`
The header name used to set the request-id. See [the request-id](https://fastify.dev/docs/v5.3.x/Reference/Logging/#logging-request-id)
section. Setting `requestIdHeader` to `true` will set the `requestIdHeader` to `"request-id"`. Setting `requestIdHeader` to a non-empty string will use the specified string as the `requestIdHeader`. By default `requestIdHeader` is set to `false` and will immediately use [genReqId](https://fastify.dev/docs/v5.3.x/Reference/Server/#genreqid)
. Setting `requestIdHeader` to an empty String (`""`) will set the requestIdHeader to `false`.
* Default: `false`
const fastify = require('fastify')({ requestIdHeader: 'x-custom-id', // -> use 'X-Custom-Id' header if available //requestIdHeader: false, // -> always use genReqId})
### `requestIdLogLabel`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidloglabel "Direct link to requestidloglabel")
* Default: `'reqId'`
Defines the label used for the request identifier when logging the request.
### `genReqId`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#genreqid "Direct link to genreqid")
* Default: `value of 'request-id' header if provided or monotonically increasing integers`
Function for generating the request-id. It will receive the _raw_ incoming request as a parameter. This function is expected to be error-free.
Especially in distributed systems, you may want to override the default ID generation behavior as shown below. For generating `UUID`s you may want to check out [hyperid](https://github.com/mcollina/hyperid)
.
> 🛈 Note: `genReqId` will be not called if the header set in `[requestIdHeader](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidheader) ` is available (defaults to 'request-id').
let i = 0const fastify = require('fastify')({ genReqId: function (req) { return i++ }})
### `trustProxy`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#trustproxy "Direct link to trustproxy")
* Default: `false`
* `true/false`: Trust all proxies (`true`) or do not trust any proxies (`false`).
* `string`: Trust only given IP/CIDR (e.g. `'127.0.0.1'`). May be a list of comma separated values (e.g. `'127.0.0.1,192.168.1.1/24'`).
* `Array`: Trust only given IP/CIDR list (e.g. `['127.0.0.1']`).
* `number`: Trust the nth hop from the front-facing proxy server as the client.
* `Function`: Custom trust function that takes `address` as first argument
function myTrustFn(address, hop) { return address === '1.2.3.4' || hop === 1}
By enabling the `trustProxy` option, Fastify will know that it is sitting behind a proxy and that the `X-Forwarded-*` header fields may be trusted, which otherwise may be easily spoofed.
const fastify = Fastify({ trustProxy: true })
For more examples, refer to the [`@fastify/proxy-addr`](https://www.npmjs.com/package/@fastify/proxy-addr)
package.
You may access the `ip`, `ips`, `host` and `protocol` values on the [`request`](https://fastify.dev/docs/v5.3.x/Reference/Request/)
object.
fastify.get('/', (request, reply) => { console.log(request.ip) console.log(request.ips) console.log(request.host) console.log(request.protocol)})
> 🛈 Note: If a request contains multiple `x-forwarded-host` or `x-forwarded-proto` headers, it is only the last one that is used to derive `request.hostname` and `request.protocol`.
### `pluginTimeout`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#plugintimeout "Direct link to plugintimeout")
* Default: `10000`
The maximum amount of time in _milliseconds_ in which a plugin can load. If not, [`ready`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ready)
will complete with an `Error` with code `'ERR_AVVIO_PLUGIN_TIMEOUT'`. When set to `0`, disables this check. This controls [avvio](https://www.npmjs.com/package/avvio)
's `timeout` parameter.
### `querystringParser`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#querystringparser "Direct link to querystringparser")
The default query string parser that Fastify uses is a more performant fork of Node.js's core `querystring` module called [`fast-querystring`](https://github.com/anonrig/fast-querystring)
.
You can use this option to use a custom parser, such as [`qs`](https://www.npmjs.com/package/qs)
.
If you only want the keys (and not the values) to be case insensitive we recommend using a custom parser to convert only the keys to lowercase.
const qs = require('qs')const fastify = require('fastify')({ querystringParser: str => qs.parse(str)})
You can also use Fastify's default parser but change some handling behavior, like the example below for case insensitive keys and values:
const querystring = require('fast-querystring')const fastify = require('fastify')({ querystringParser: str => querystring.parse(str.toLowerCase())})
### `exposeHeadRoutes`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#exposeheadroutes "Direct link to exposeheadroutes")
* Default: `true`
Automatically creates a sibling `HEAD` route for each `GET` route defined. If you want a custom `HEAD` handler without disabling this option, make sure to define it before the `GET` route.
### `constraints`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#constraints "Direct link to constraints")
Fastify's built-in route constraints are provided by `find-my-way`, which allows constraining routes by `version` or `host`. You can add new constraint strategies, or override the built-in strategies, by providing a `constraints` object with strategies for `find-my-way`. You can find more information on constraint strategies in the [find-my-way](https://github.com/delvedor/find-my-way)
documentation.
const customVersionStrategy = { storage: function () { const versions = {} return { get: (version) => { return versions[version] || null }, set: (version, store) => { versions[version] = store } } }, deriveVersion: (req, ctx) => { return req.headers['accept'] }}const fastify = require('fastify')({ constraints: { version: customVersionStrategy }})
### `return503OnClosing`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#return503onclosing "Direct link to return503onclosing")
* Default: `true`
Returns 503 after calling `close` server method. If `false`, the server routes the incoming request as usual.
### `ajv`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#ajv "Direct link to ajv")
Configure the Ajv v8 instance used by Fastify without providing a custom one. The default configuration is explained in the [#schema-validator](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schema-validator)
section.
const fastify = require('fastify')({ ajv: { customOptions: { removeAdditional: 'all' // Refer to [ajv options](https://ajv.js.org/options.html#removeadditional) }, plugins: [ require('ajv-merge-patch'), [require('ajv-keywords'), 'instanceof'] // Usage: [plugin, pluginOptions] - Plugin with options // Usage: plugin - Plugin without options ] }})
### `serializerOpts`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#serializeropts "Direct link to serializeropts")
Customize the options of the default [`fast-json-stringify`](https://github.com/fastify/fast-json-stringify#options)
instance that serializes the response's payload:
const fastify = require('fastify')({ serializerOpts: { rounding: 'ceil' }})
### `http2SessionTimeout`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2sessiontimeout "Direct link to http2sessiontimeout")
* Default: `72000`
Set a default [timeout](https://nodejs.org/api/http2.html#http2sessionsettimeoutmsecs-callback)
to every incoming HTTP/2 session in milliseconds. The session will be closed on the timeout.
This option is needed to offer a graceful "close" experience when using HTTP/2. The low default has been chosen to mitigate denial of service attacks. When the server is behind a load balancer or can scale automatically this value can be increased to fit the use case. Node core defaults this to `0`.
### `frameworkErrors`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#frameworkerrors "Direct link to frameworkerrors")
* Default: `null`
Fastify provides default error handlers for the most common use cases. It is possible to override one or more of those handlers with custom code using this option.
> 🛈 Note: Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at present.
const fastify = require('fastify')({ frameworkErrors: function (error, req, res) { if (error instanceof FST_ERR_BAD_URL) { res.code(400) return res.send("Provided url is not valid") } else if(error instanceof FST_ERR_ASYNC_CONSTRAINT) { res.code(400) return res.send("Provided header is not valid") } else { res.send(err) } }})
### `clientErrorHandler`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#clienterrorhandler "Direct link to clienterrorhandler")
Set a [clientErrorHandler](https://nodejs.org/api/http.html#http_event_clienterror)
that listens to `error` events emitted by client connections and responds with a `400`.
It is possible to override the default `clientErrorHandler` using this option.
* Default:
function defaultClientErrorHandler (err, socket) { if (err.code === 'ECONNRESET') { return } const body = JSON.stringify({ error: http.STATUS_CODES['400'], message: 'Client Error', statusCode: 400 }) this.log.trace({ err }, 'client error') if (socket.writable) { socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) }}
> 🛈 Note: `clientErrorHandler` operates with raw sockets. The handler is expected to return a properly formed HTTP response that includes a status line, HTTP headers and a message body. Before attempting to write the socket, the handler should check if the socket is still writable as it may have already been destroyed.
const fastify = require('fastify')({ clientErrorHandler: function (err, socket) { const body = JSON.stringify({ error: { message: 'Client error', code: '400' } }) // `this` is bound to fastify instance this.log.trace({ err }, 'client error') // the handler is responsible for generating a valid HTTP response socket.end([ 'HTTP/1.1 400 Bad Request', `Content-Length: ${body.length}`, `Content-Type: application/json\r\n\r\n${body}` ].join('\r\n')) }})
### `rewriteUrl`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#rewriteurl "Direct link to rewriteurl")
Set a sync callback function that must return a string that allows rewriting URLs. This is useful when you are behind a proxy that changes the URL. Rewriting a URL will modify the `url` property of the `req` object.
Note that `rewriteUrl` is called _before_ routing, it is not encapsulated and it is an instance-wide configuration.
// @param {object} req The raw Node.js HTTP request, not the `FastifyRequest` object.// @this Fastify The root Fastify instance (not an encapsulated instance).// @returns {string} The path that the request should be mapped to.function rewriteUrl (req) { if (req.url === '/hi') { this.log.debug({ originalUrl: req.url, url: '/hello' }, 'rewrite url'); return '/hello' } else { return req.url; }}
### `useSemicolonDelimiter`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#usesemicolondelimiter "Direct link to usesemicolondelimiter")
* Default `false`
Fastify uses [find-my-way](https://github.com/delvedor/find-my-way)
which supports, separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`. This decision originated from \[delvedor/find-my-way#76\] ([https://github.com/delvedor/find-my-way/issues/76](https://github.com/delvedor/find-my-way/issues/76)
). Thus, this option will support backwards compatiblilty for the need to split on `;`. To enable support for splitting on `;` set `useSemicolonDelimiter` to `true`.
const fastify = require('fastify')({ useSemicolonDelimiter: true})fastify.get('/dev', async (request, reply) => { // An example request such as `/dev;foo=bar` // Will produce the following query params result `{ foo = 'bar' }` return request.query})
Instance[](https://fastify.dev/docs/v5.3.x/Reference/Server/#instance "Direct link to Instance")
--------------------------------------------------------------------------------------------------
### Server Methods[](https://fastify.dev/docs/v5.3.x/Reference/Server/#server-methods "Direct link to Server Methods")
#### server[](https://fastify.dev/docs/v5.3.x/Reference/Server/#server "Direct link to server")
`fastify.server`: The Node core [server](https://nodejs.org/api/http.html#http_class_http_server)
object as returned by the [**`Fastify factory function`**](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory)
.
> ⚠ Warning: If utilized improperly, certain Fastify features could be disrupted. It is recommended to only use it for attaching listeners.
#### after[](https://fastify.dev/docs/v5.3.x/Reference/Server/#after "Direct link to after")
Invoked when the current plugin and all the plugins that have been registered within it have finished loading. It is always executed before the method `fastify.ready`.
fastify .register((instance, opts, done) => { console.log('Current plugin') done() }) .after(err => { console.log('After current plugin') }) .register((instance, opts, done) => { console.log('Next plugin') done() }) .ready(err => { console.log('Everything has been loaded') })
In case `after()` is called without a function, it returns a `Promise`:
fastify.register(async (instance, opts) => { console.log('Current plugin')})await fastify.after()console.log('After current plugin')fastify.register(async (instance, opts) => { console.log('Next plugin')})await fastify.ready()console.log('Everything has been loaded')
#### ready[](https://fastify.dev/docs/v5.3.x/Reference/Server/#ready "Direct link to ready")
Function called when all the plugins have been loaded. It takes an error parameter if something went wrong.
fastify.ready(err => { if (err) throw err})
If it is called without any arguments, it will return a `Promise`:
fastify.ready().then(() => { console.log('successfully booted!')}, (err) => { console.log('an error happened', err)})
#### listen[](https://fastify.dev/docs/v5.3.x/Reference/Server/#listen "Direct link to listen")
Starts the server and internally waits for the `.ready()` event. The signature is `.listen([options][, callback])`. Both the `options` object and the `callback` parameters extend the [Node.js core](https://nodejs.org/api/net.html#serverlistenoptions-callback)
options object. Thus, all core options are available with the following additional Fastify specific options:
### `listenTextResolver`[](https://fastify.dev/docs/v5.3.x/Reference/Server/#listentextresolver "Direct link to listentextresolver")
Set an optional resolver for the text to log after server has been successfully started. It is possible to override the default `Server listening at [address]` log entry using this option.
server.listen({ port: 9080, listenTextResolver: (address) => { return `Prometheus metrics server is listening at ${address}` }})
By default, the server will listen on the address(es) resolved by `localhost` when no specific host is provided. If listening on any available interface is desired, then specifying `0.0.0.0` for the address will listen on all IPv4 addresses. The address argument provided above will then return the first such IPv4 address. The following table details the possible values for `host` when targeting `localhost`, and what the result of those values for `host` will be.
| Host | IPv4 | IPv6 |
| --- | --- | --- |
| `::` | ✅\* | ✅ |
| `::` + [`ipv6Only`](https://nodejs.org/api/net.html#serverlistenoptions-callback) | 🚫 | ✅ |
| `0.0.0.0` | ✅ | 🚫 |
| `localhost` | ✅ | ✅ |
| `127.0.0.1` | ✅ | 🚫 |
| `::1` | 🚫 | ✅ |
\* Using `::` for the address will listen on all IPv6 addresses and, depending on OS, may also listen on [all IPv4 addresses](https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback)
.
Be careful when deciding to listen on all interfaces; it comes with inherent [security risks](https://web.archive.org/web/20170831174611/https://snyk.io/blog/mongodb-hack-and-secure-defaults/)
.
The default is to listen on `port: 0` (which picks the first available open port) and `host: 'localhost'`:
fastify.listen((err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
Specifying an address is also supported:
fastify.listen({ port: 3000, host: '127.0.0.1' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
If no callback is provided a Promise is returned:
fastify.listen({ port: 3000 }) .then((address) => console.log(`server listening on ${address}`)) .catch(err => { console.log('Error starting server:', err) process.exit(1) })
When deploying to a Docker, and potentially other, containers, it is advisable to listen on `0.0.0.0` because they do not default to exposing mapped ports to `localhost`:
fastify.listen({ port: 3000, host: '0.0.0.0' }, (err, address) => { if (err) { fastify.log.error(err) process.exit(1) }})
If the `port` is omitted (or is set to zero), a random available port is automatically chosen (available via `fastify.server.address().port`).
The default options of listen are:
fastify.listen({ port: 0, host: 'localhost', exclusive: false, readableAll: false, writableAll: false, ipv6Only: false}, (err) => {})
#### addresses[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addresses "Direct link to addresses")
This method returns an array of addresses that the server is listening on. If you call it before `listen()` is called or after the `close()` function, it will return an empty array.
await fastify.listen({ port: 8080 })const addresses = fastify.addresses()// [// { port: 8080, family: 'IPv6', address: '::1' },// { port: 8080, family: 'IPv4', address: '127.0.0.1' }// ]
Note that the array contains the `fastify.server.address()` too.
#### routing[](https://fastify.dev/docs/v5.3.x/Reference/Server/#routing "Direct link to routing")
Method to access the `lookup` method of the internal router and match the request to the appropriate handler:
fastify.routing(req, res)
#### route[](https://fastify.dev/docs/v5.3.x/Reference/Server/#route "Direct link to route")
Method to add routes to the server, it also has shorthand functions, check [here](https://fastify.dev/docs/v5.3.x/Reference/Routes/)
.
#### hasRoute[](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasroute "Direct link to hasRoute")
Method to check if a route is already registered to the internal router. It expects an object as the payload. `url` and `method` are mandatory fields. It is possible to also specify `constraints`. The method returns `true` if the route is registered or `false` if not.
const routeExists = fastify.hasRoute({ url: '/', method: 'GET', constraints: { version: '1.0.0' } // optional})if (routeExists === false) { // add route}
#### findRoute[](https://fastify.dev/docs/v5.3.x/Reference/Server/#findroute "Direct link to findRoute")
Method to retrieve a route already registered to the internal router. It expects an object as the payload. `url` and `method` are mandatory fields. It is possible to also specify `constraints`. The method returns a route object or `null` if the route cannot be found.
const route = fastify.findRoute({ url: '/artists/:artistId', method: 'GET', constraints: { version: '1.0.0' } // optional})if (route !== null) { // perform some route checks console.log(route.params) // `{artistId: ':artistId'}`}
#### close[](https://fastify.dev/docs/v5.3.x/Reference/Server/#close "Direct link to close")
`fastify.close(callback)`: call this function to close the server instance and run the [`'onClose'`](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#on-close)
hook.
Calling `close` will also cause the server to respond to every new incoming request with a `503` error and destroy that request. See [`return503OnClosing` flags](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory-return-503-on-closing)
for changing this behavior.
If it is called without any arguments, it will return a Promise:
fastify.close().then(() => { console.log('successfully closed!')}, (err) => { console.log('an error happened', err)})
#### decorate\*[](https://fastify.dev/docs/v5.3.x/Reference/Server/#decorate "Direct link to decorate*")
Function useful if you need to decorate the fastify instance, Reply or Request, check [here](https://fastify.dev/docs/v5.3.x/Reference/Decorators/)
.
#### register[](https://fastify.dev/docs/v5.3.x/Reference/Server/#register "Direct link to register")
Fastify allows the user to extend its functionality with plugins. A plugin can be a set of routes, a server decorator, or whatever, check [here](https://fastify.dev/docs/v5.3.x/Reference/Plugins/)
.
#### addHook[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addhook "Direct link to addHook")
Function to add a specific hook in the lifecycle of Fastify, check [here](https://fastify.dev/docs/v5.3.x/Reference/Hooks/)
.
#### prefix[](https://fastify.dev/docs/v5.3.x/Reference/Server/#prefix "Direct link to prefix")
The full path that will be prefixed to a route.
Example:
fastify.register(function (instance, opts, done) { instance.get('/foo', function (request, reply) { // Will log "prefix: /v1" request.log.info('prefix: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) instance.register(function (instance, opts, done) { instance.get('/bar', function (request, reply) { // Will log "prefix: /v1/v2" request.log.info('prefix: %s', instance.prefix) reply.send({ prefix: instance.prefix }) }) done() }, { prefix: '/v2' }) done()}, { prefix: '/v1' })
#### pluginName[](https://fastify.dev/docs/v5.3.x/Reference/Server/#pluginname "Direct link to pluginName")
Name of the current plugin. The root plugin is called `'fastify'`. There are different ways to define a name (in order).
1. If you use [fastify-plugin](https://github.com/fastify/fastify-plugin)
the metadata `name` is used.
2. If the exported plugin has the `Symbol.for('fastify.display-name')` property, then the value of that property is used. Example: `pluginFn[Symbol.for('fastify.display-name')] = "Custom Name"`
3. If you `module.exports` a plugin the filename is used.
4. If you use a regular [function declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#Defining_functions)
the function name is used.
_Fallback_: The first two lines of your plugin will represent the plugin name. Newlines are replaced by `--`. This will help to identify the root cause when you deal with many plugins.
> ⚠ Warning: If you have to deal with nested plugins, the name differs with the usage of the [fastify-plugin](https://github.com/fastify/fastify-plugin)
> because no new scope is created and therefore we have no place to attach contextual data. In that case, the plugin name will represent the boot order of all involved plugins in the format of `fastify -> plugin-A -> plugin-B`.
#### hasPlugin[](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasplugin "Direct link to hasPlugin")
Method to check if a specific plugin has been registered. Relies on the plugin metadata name. Returns `true` if the plugin is registered. Otherwise, returns `false`.
const fastify = require('fastify')()fastify.register(require('@fastify/cookie'), { secret: 'my-secret', parseOptions: {}})fastify.ready(() => { fastify.hasPlugin('@fastify/cookie') // true})
### listeningOrigin[](https://fastify.dev/docs/v5.3.x/Reference/Server/#listeningorigin "Direct link to listeningOrigin")
The current origin the server is listening to. For example, a TCP socket based server returns a base address like `http://127.0.0.1:3000`, and a Unix socket server will return the socket path, e.g. `fastify.temp.sock`.
#### log[](https://fastify.dev/docs/v5.3.x/Reference/Server/#log "Direct link to log")
The logger instance, check [here](https://fastify.dev/docs/v5.3.x/Reference/Logging/)
.
#### version[](https://fastify.dev/docs/v5.3.x/Reference/Server/#version "Direct link to version")
Fastify version of the instance. Used for plugin support. See [Plugins](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#handle-the-scope)
for information on how the version is used by plugins.
#### inject[](https://fastify.dev/docs/v5.3.x/Reference/Server/#inject "Direct link to inject")
Fake HTTP injection (for testing purposes) [here](https://fastify.dev/docs/v5.3.x/Guides/Testing/#benefits-of-using-fastifyinject)
.
#### addHttpMethod[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addhttpmethod "Direct link to addHttpMethod")
Fastify supports the `GET`, `HEAD`, `TRACE`, `DELETE`, `OPTIONS`, `PATCH`, `PUT` and `POST` HTTP methods by default. The `addHttpMethod` method allows to add any non standard HTTP methods to the server that are [supported by Node.js](https://nodejs.org/api/http.html#httpmethods)
.
// Add a new HTTP method called 'MKCOL' that supports a request bodyfastify.addHttpMethod('MKCOL', { hasBody: true, })// Add a new HTTP method called 'COPY' that does not support a request bodyfastify.addHttpMethod('COPY')
After calling `addHttpMethod`, it is possible to use the route shorthand methods to define routes for the new HTTP method:
fastify.addHttpMethod('MKCOL', { hasBody: true })fastify.mkcol('/', (req, reply) => { // Handle the 'MKCOL' request})
#### addSchema[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addschema "Direct link to addSchema")
`fastify.addSchema(schemaObj)`, adds a JSON schema to the Fastify instance. This allows you to reuse it everywhere in your application just by using the standard `$ref` keyword.
To learn more, read the [Validation and Serialization](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/)
documentation.
#### getSchemas[](https://fastify.dev/docs/v5.3.x/Reference/Server/#getschemas "Direct link to getSchemas")
`fastify.getSchemas()`, returns a hash of all schemas added via `.addSchema`. The keys of the hash are the `$id`s of the JSON Schema provided.
#### getSchema[](https://fastify.dev/docs/v5.3.x/Reference/Server/#getschema "Direct link to getSchema")
`fastify.getSchema(id)`, return the JSON schema added with `.addSchema` and the matching `id`. It returns `undefined` if it is not found.
#### setReplySerializer[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setreplyserializer "Direct link to setReplySerializer")
Set the reply serializer for all the routes. This will be used as default if a [Reply.serializer(func)](https://fastify.dev/docs/v5.3.x/Reference/Reply/#serializerfunc)
has not been set. The handler is fully encapsulated, so different plugins can set different error handlers. Note: the function parameter is called only for status `2xx`. Check out the [`setErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler)
for errors.
fastify.setReplySerializer(function (payload, statusCode){ // serialize the payload with a sync function return `my serialized ${statusCode} content: ${payload}`})
#### setValidatorCompiler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setvalidatorcompiler "Direct link to setValidatorCompiler")
Set the schema validator compiler for all routes. See [#schema-validator](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schema-validator)
.
#### setSchemaErrorFormatter[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setschemaerrorformatter "Direct link to setSchemaErrorFormatter")
Set the schema error formatter for all routes. See [#error-handling](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schemaerrorformatter)
.
#### setSerializerCompiler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setserializercompiler "Direct link to setSerializerCompiler")
Set the schema serializer compiler for all routes. See [#schema-serializer](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schema-serializer)
.
> 🛈 Note: [`setReplySerializer`](https://fastify.dev/docs/v5.3.x/Reference/Server/#set-reply-serializer)
> has priority if set!
#### validatorCompiler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#validatorcompiler "Direct link to validatorCompiler")
This property can be used to get the schema validator. If not set, it will be `null` until the server starts, then it will be a function with the signature `function ({ schema, method, url, httpPart })` that returns the input `schema` compiled to a function for validating data. The input `schema` can access all the shared schemas added with [`.addSchema`](https://fastify.dev/docs/v5.3.x/Reference/Server/#add-schema)
function.
#### serializerCompiler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#serializercompiler "Direct link to serializerCompiler")
This property can be used to get the schema serializer. If not set, it will be `null` until the server starts, then it will be a function with the signature `function ({ schema, method, url, httpPart })` that returns the input `schema` compiled to a function for validating data. The input `schema` can access all the shared schemas added with [`.addSchema`](https://fastify.dev/docs/v5.3.x/Reference/Server/#add-schema)
function.
#### schemaErrorFormatter[](https://fastify.dev/docs/v5.3.x/Reference/Server/#schemaerrorformatter "Direct link to schemaErrorFormatter")
This property can be used to set a function to format errors that happen while the `validationCompiler` fails to validate the schema. See [#error-handling](https://fastify.dev/docs/v5.3.x/Reference/Validation-and-Serialization/#schemaerrorformatter)
.
#### schemaController[](https://fastify.dev/docs/v5.3.x/Reference/Server/#schemacontroller "Direct link to schemaController")
This property can be used to fully manage:
* `bucket`: where the schemas of your application will be stored
* `compilersFactory`: what module must compile the JSON schemas
It can be useful when your schemas are stored in another data structure that is unknown to Fastify.
Another use case is to tweak all the schemas processing. Doing so it is possible to use Ajv v8 JTD or Standalone feature. To use such as JTD or the Standalone mode, refers to the [`@fastify/ajv-compiler` documentation](https://github.com/fastify/ajv-compiler#usage)
.
const fastify = Fastify({ schemaController: { /** * This factory is called whenever `fastify.register()` is called. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} parentSchemas these schemas will be returned by the * `getSchemas()` method function of the returned `bucket`. */ bucket: function factory (parentSchemas) { return { add (inputSchema) { // This function must store the schema added by the user. // This function is invoked when `fastify.addSchema()` is called. }, getSchema (schema$id) { // This function must return the raw schema requested by the `schema$id`. // This function is invoked when `fastify.getSchema(id)` is called. return aSchema }, getSchemas () { // This function must return all the schemas referenced by the routes schemas' $ref // It must return a JSON where the property is the schema `$id` and the value is the raw JSON Schema. const allTheSchemaStored = { 'schema$id1': schema1, 'schema$id2': schema2 } return allTheSchemaStored } } }, /** * The compilers factory lets you fully control the validator and serializer * in the Fastify's lifecycle, providing the encapsulation to your compilers. */ compilersFactory: { /** * This factory is called whenever a new validator instance is needed. * It may be called whenever `fastify.register()` is called only if new schemas have been added to the * encapsulation context. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} externalSchemas these schemas will be returned by the * `bucket.getSchemas()`. Needed to resolve the external references $ref. * @param {object} ajvServerOption the server `ajv` options to build your compilers accordingly */ buildValidator: function factory (externalSchemas, ajvServerOption) { // This factory function must return a schema validator compiler. // See [#schema-validator](./Validation-and-Serialization.md#schema-validator) for details. const yourAjvInstance = new Ajv(ajvServerOption.customOptions) return function validatorCompiler ({ schema, method, url, httpPart }) { return yourAjvInstance.compile(schema) } }, /** * This factory is called whenever a new serializer instance is needed. * It may be called whenever `fastify.register()` is called only if new schemas have been added to the * encapsulation context. * It may receive as input the schemas of the parent context if some schemas have been added. * @param {object} externalSchemas these schemas will be returned by the * `bucket.getSchemas()`. Needed to resolve the external references $ref. * @param {object} serializerOptsServerOption the server `serializerOpts` * options to build your compilers accordingly */ buildSerializer: function factory (externalSchemas, serializerOptsServerOption) { // This factory function must return a schema serializer compiler. // See [#schema-serializer](./Validation-and-Serialization.md#schema-serializer) for details. return function serializerCompiler ({ schema, method, url, httpStatus, contentType }) { return data => JSON.stringify(data) } } } }});
#### setNotFoundHandler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setnotfoundhandler "Direct link to setNotFoundHandler")
`fastify.setNotFoundHandler(handler(request, reply))`: set the 404 handler. This call is encapsulated by prefix, so different plugins can set different not found handlers if a different [`prefix` option](https://fastify.dev/docs/v5.3.x/Reference/Plugins/#route-prefixing-option)
is passed to `fastify.register()`. The handler is treated as a regular route handler so requests will go through the full [Fastify lifecycle](https://fastify.dev/docs/v5.3.x/Reference/Lifecycle/#lifecycle)
. _async-await_ is supported as well.
You can also register [`preValidation`](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-hooks)
and [`preHandler`](https://fastify.dev/docs/v5.3.x/Reference/Hooks/#route-hooks)
hooks for the 404 handler.
> 🛈 Note: The `preValidation` hook registered using this method will run for a route that Fastify does not recognize and **not** when a route handler manually calls [`reply.callNotFound`](https://fastify.dev/docs/v5.3.x/Reference/Reply/#call-not-found)
> . In which case, only preHandler will be run.
fastify.setNotFoundHandler({ preValidation: (req, reply, done) => { // your code done() }, preHandler: (req, reply, done) => { // your code done() }}, function (request, reply) { // Default not found handler with preValidation and preHandler hooks})fastify.register(function (instance, options, done) { instance.setNotFoundHandler(function (request, reply) { // Handle not found request without preValidation and preHandler hooks // to URLs that begin with '/v1' }) done()}, { prefix: '/v1' })
Fastify calls setNotFoundHandler to add a default 404 handler at startup before plugins are registered. If you would like to augment the behavior of the default 404 handler, for example with plugins, you can call setNotFoundHandler with no arguments `fastify.setNotFoundHandler()` within the context of these registered plugins.
> 🛈 Note: Some config properties from the request object will be undefined inside the custom not found handler. E.g.: `request.routeOptions.url`, `routeOptions.method` and `routeOptions.config`. This method design goal is to allow calling the common not found route. To return a per-route customized 404 response, you can do it in the response itself.
#### setErrorHandler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#seterrorhandler "Direct link to setErrorHandler")
`fastify.setErrorHandler(handler(error, request, reply))`: Set a function that will be called whenever an error happens. The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set different error handlers. _async-await_ is supported as well.
If the error `statusCode` is less than 400, Fastify will automatically set it to 500 before calling the error handler.
`setErrorHandler` will _**not**_ catch:
* errors thrown in an `onResponse` hook because the response has already been sent to the client. Use the `onSend` hook instead.
* not found (404) errors. Use [`setNotFoundHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#set-not-found-handler)
instead.
fastify.setErrorHandler(function (error, request, reply) { // Log error this.log.error(error) // Send error response reply.status(409).send({ ok: false })})
Fastify is provided with a default function that is called if no error handler is set. It can be accessed using `fastify.errorHandler` and it logs the error with respect to its `statusCode`.
const statusCode = error.statusCodeif (statusCode >= 500) { log.error(error)} else if (statusCode >= 400) { log.info(error)} else { log.error(error)}
> ⚠ Warning: Avoid calling setErrorHandler multiple times in the same scope. Only the last handler will take effect, and previous ones will be silently overridden.
>
> Incorrect usage:
>
> app.setErrorHandler(function freeSomeResources () { // Never executed, memory leaks})app.setErrorHandler(function anotherErrorHandler () { // Overrides the previous handler})
#### setChildLoggerFactory[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setchildloggerfactory "Direct link to setChildLoggerFactory")
`fastify.setChildLoggerFactory(factory(logger, bindings, opts, rawReq))`: Set a function that will be called when creating a child logger instance for each request which allows for modifying or adding child logger bindings and logger options, or returning a custom child logger implementation.
Child logger bindings have a performance advantage over per-log bindings because they are pre-serialized by Pino when the child logger is created.
The first parameter is the parent logger instance, followed by the default bindings and logger options which should be passed to the child logger, and finally the raw request (not a Fastify request object). The function is bound with `this` being the Fastify instance.
For example:
const fastify = require('fastify')({ childLoggerFactory: function (logger, bindings, opts, rawReq) { // Calculate additional bindings from the request if needed bindings.traceContext = rawReq.headers['x-cloud-trace-context'] return logger.child(bindings, opts) }})
The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set different logger factories.
#### setGenReqId[](https://fastify.dev/docs/v5.3.x/Reference/Server/#setgenreqid "Direct link to setGenReqId")
`fastify.setGenReqId(function (rawReq))` Synchronous function for setting the request-id for additional Fastify instances. It will receive the _raw_ incoming request as a parameter. The provided function should not throw an Error in any case.
Especially in distributed systems, you may want to override the default ID generation behavior to handle custom ways of generating different IDs in order to handle different use cases. Such as observability or webhooks plugins.
For example:
const fastify = require('fastify')({ genReqId: (req) => { return 'base' }})fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // custom request ID for `/webhooks` return 'webhooks-id' }) done()}, { prefix: '/webhooks' })fastify.register((instance, opts, done) => { instance.setGenReqId((req) => { // custom request ID for `/observability` return 'observability-id' }) done()}, { prefix: '/observability' })
The handler is bound to the Fastify instance and is fully encapsulated, so different plugins can set a different request ID.
#### addConstraintStrategy[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addconstraintstrategy "Direct link to addConstraintStrategy")
Function to add a custom constraint strategy. To register a new type of constraint, you must add a new constraint strategy that knows how to match values to handlers, and that knows how to get the constraint value from a request.
Add a custom constraint strategy using the `fastify.addConstraintStrategy` method:
const customResponseTypeStrategy = { // strategy name for referencing in the route handler `constraints` options name: 'accept', // storage factory for storing routes in the find-my-way route tree storage: function () { let handlers = {} return { get: (type) => { return handlers[type] || null }, set: (type, store) => { handlers[type] = store } } }, // function to get the value of the constraint from each incoming request deriveConstraint: (req, ctx) => { return req.headers['accept'] }, // optional flag marking if handlers without constraints can match requests that have a value for this constraint mustMatchWhenDerived: true}const router = Fastify();router.addConstraintStrategy(customResponseTypeStrategy);
#### hasConstraintStrategy[](https://fastify.dev/docs/v5.3.x/Reference/Server/#hasconstraintstrategy "Direct link to hasConstraintStrategy")
The `fastify.hasConstraintStrategy(strategyName)` checks if there already exists a custom constraint strategy with the same name.
#### printRoutes[](https://fastify.dev/docs/v5.3.x/Reference/Server/#printroutes "Direct link to printRoutes")
`fastify.printRoutes()`: Fastify router builds a tree of routes for each HTTP method. If you call the prettyPrint without specifying an HTTP method, it will merge all the trees into one and print it. The merged tree doesn't represent the internal router structure. **Do not use it for debugging.**
_Remember to call it inside or after a `ready` call._
fastify.get('/test', () => {})fastify.get('/test/hello', () => {})fastify.get('/testing', () => {})fastify.get('/testing/:param', () => {})fastify.put('/update', () => {})fastify.ready(() => { console.log(fastify.printRoutes()) // └── / // ├── test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── / // │ └── :param (GET) // └── update (PUT)})
If you want to print the internal router tree, you should specify the `method` param. Printed tree will represent the internal router structure. **You can use it for debugging.**
console.log(fastify.printRoutes({ method: 'GET' })) // └── / // └── test (GET) // ├── /hello (GET) // └── ing (GET) // └── / // └── :param (GET) console.log(fastify.printRoutes({ method: 'PUT' })) // └── / // └── update (PUT)
`fastify.printRoutes({ commonPrefix: false })` will print compressed trees. This may be useful when you have a large number of routes with common prefixes. It doesn't represent the internal router structure. **Do not use it for debugging.**
console.log(fastify.printRoutes({ commonPrefix: false })) // ├── /test (GET) // │ ├── /hello (GET) // │ └── ing (GET) // │ └── /:param (GET) // └── /update (PUT)
`fastify.printRoutes({ includeMeta: (true | []) })` will display properties from the `route.store` object for each displayed route. This can be an `array` of keys (e.g. `['onRequest', Symbol('key')]`), or `true` to display all properties. A shorthand option, `fastify.printRoutes({ includeHooks: true })` will include all [hooks](https://fastify.dev/docs/v5.3.x/Reference/Hooks/)
.
fastify.get('/test', () => {}) fastify.get('/test/hello', () => {}) const onTimeout = () => {} fastify.addHook('onRequest', () => {}) fastify.addHook('onTimeout', onTimeout) console.log(fastify.printRoutes({ includeHooks: true, includeMeta: ['errorHandler'] })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()" // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (errorHandler) "defaultErrorHandler()" // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // • (errorHandler) "defaultErrorHandler()" console.log(fastify.printRoutes({ includeHooks: true })) // └── / // └── test (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // test (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"] // └── /hello (GET) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // /hello (HEAD) // • (onTimeout) ["onTimeout()"] // • (onRequest) ["anonymous()"] // • (onSend) ["headRouteOnSendHandler()"]
#### printPlugins[](https://fastify.dev/docs/v5.3.x/Reference/Server/#printplugins "Direct link to printPlugins")
`fastify.printPlugins()`: Prints the representation of the internal plugin tree used by the avvio, useful for debugging require order issues.
_Remember to call it inside or after a `ready` call._
fastify.register(async function foo (instance) { instance.register(async function bar () {})})fastify.register(async function baz () {})fastify.ready(() => { console.error(fastify.printPlugins()) // will output the following to stderr: // └── root // ├── foo // │ └── bar // └── baz})
#### addContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/Server/#addcontenttypeparser "Direct link to addContentTypeParser")
`fastify.addContentTypeParser(content-type, options, parser)` is used to pass a custom parser for a given content type. Useful for adding parsers for custom content types, e.g. `text/json, application/vnd.oasis.opendocument.text`. `content-type` can be a string, string array or RegExp.
// The two arguments passed to getDefaultJsonParser are for ProtoType poisoning// and Constructor Poisoning configuration respectively. The possible values are// 'ignore', 'remove', 'error'. ignore skips all validations and it is similar// to calling JSON.parse() directly. See the// [`secure-json-parse` documentation](https://github.com/fastify/secure-json-parse#api) for more information.fastify.addContentTypeParser('text/json', { asString: true }, fastify.getDefaultJsonParser('ignore', 'ignore'))
#### hasContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/Server/#hascontenttypeparser "Direct link to hasContentTypeParser")
`fastify.hasContentTypeParser(contentType)` is used to check whether there is a content type parser in the current context for the specified content type.
fastify.hasContentTypeParser('text/json')fastify.hasContentTypeParser(/^.+\/json$/)
#### removeContentTypeParser[](https://fastify.dev/docs/v5.3.x/Reference/Server/#removecontenttypeparser "Direct link to removeContentTypeParser")
`fastify.removeContentTypeParser(contentType)` is used to remove content type parsers in the current context. This method allows for example to remove the both built-in parsers for `application/json` and `text/plain`.
fastify.removeContentTypeParser('application/json')fastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.3.x/Reference/Server/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
The `fastify.removeAllContentTypeParsers()` method allows all content type parsers in the current context to be removed. A use case of this method is the implementation of catch-all content type parser. Before adding this parser with `fastify.addContentTypeParser()` one could call the `removeAllContentTypeParsers` method.
For more details about the usage of the different content type parser APIs see [here](https://fastify.dev/docs/v5.3.x/Reference/ContentTypeParser/#usage)
.
#### getDefaultJsonParser[](https://fastify.dev/docs/v5.3.x/Reference/Server/#getdefaultjsonparser "Direct link to getDefaultJsonParser")
`fastify.getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning)` takes two arguments. First argument is ProtoType poisoning configuration and second argument is constructor poisoning configuration. See the [`secure-json-parse` documentation](https://github.com/fastify/secure-json-parse#api)
for more information.
#### defaultTextParser[](https://fastify.dev/docs/v5.3.x/Reference/Server/#defaulttextparser "Direct link to defaultTextParser")
`fastify.defaultTextParser()` can be used to parse content as plain text.
fastify.addContentTypeParser('text/json', { asString: true }, fastify.defaultTextParser)
#### errorHandler[](https://fastify.dev/docs/v5.3.x/Reference/Server/#errorhandler "Direct link to errorHandler")
`fastify.errorHandler` can be used to handle errors using fastify's default error handler.
fastify.get('/', { errorHandler: (error, request, reply) => { if (error.code === 'SOMETHING_SPECIFIC') { reply.send({ custom: 'response' }) return } fastify.errorHandler(error, request, response) }}, handler)
#### childLoggerFactory[](https://fastify.dev/docs/v5.3.x/Reference/Server/#childloggerfactory "Direct link to childLoggerFactory")
`fastify.childLoggerFactory` returns the custom logger factory function for the Fastify instance. See the [`childLoggerFactory` config option](https://fastify.dev/docs/v5.3.x/Reference/Server/#setchildloggerfactory)
for more info.
#### Symbol.asyncDispose[](https://fastify.dev/docs/v5.3.x/Reference/Server/#symbolasyncdispose "Direct link to Symbol.asyncDispose")
`fastify[Symbol.asyncDispose]` is a symbol that can be used to define an asynchronous function that will be called when the Fastify instance is closed.
It's commonly used alongside the `using` TypeScript keyword to ensure that resources are cleaned up when the Fastify instance is closed.
This combines perfectly inside short lived processes or unit tests, where you must close all Fastify resources after returning from inside the function.
test('Uses app and closes it afterwards', async () => { await using app = fastify(); // do something with app.})
In the above example, Fastify is closed automatically after the test finishes.
Read more about the [ECMAScript Explicit Resource Management](https://tc39.es/proposal-explicit-resource-management)
and the [using keyword](https://devblogs.microsoft.com/typescript/announcing-typescript-5-2/)
introduced in TypeScript 5.2.
#### initialConfig[](https://fastify.dev/docs/v5.3.x/Reference/Server/#initialconfig "Direct link to initialConfig")
`fastify.initialConfig`: Exposes a frozen read-only object registering the initial options passed down by the user to the Fastify instance.
The properties that can currently be exposed are:
* connectionTimeout
* keepAliveTimeout
* bodyLimit
* caseSensitive
* allowUnsafeRegex
* http2
* https (it will return `false`/`true` or `{ allowHTTP1: true/false }` if explicitly passed)
* ignoreTrailingSlash
* disableRequestLogging
* maxParamLength
* onProtoPoisoning
* onConstructorPoisoning
* pluginTimeout
* requestIdHeader
* requestIdLogLabel
* http2SessionTimeout
* useSemicolonDelimiter
const { readFileSync } = require('node:fs')const Fastify = require('fastify')const fastify = Fastify({ https: { allowHTTP1: true, key: readFileSync('./fastify.key'), cert: readFileSync('./fastify.cert') }, logger: { level: 'trace'}, ignoreTrailingSlash: true, maxParamLength: 200, caseSensitive: true, trustProxy: '127.0.0.1,192.168.1.1/24',})console.log(fastify.initialConfig)/*will log :{ caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200}*/fastify.register(async (instance, opts) => { instance.get('/', async (request, reply) => { return instance.initialConfig /* will return : { caseSensitive: true, https: { allowHTTP1: true }, ignoreTrailingSlash: true, maxParamLength: 200 } */ }) instance.get('/error', async (request, reply) => { // will throw an error because initialConfig is read-only // and can not be modified instance.initialConfig.https.allowHTTP1 = false return instance.initialConfig })})// Start listening.fastify.listen({ port: 3000 }, (err) => { if (err) { fastify.log.error(err) process.exit(1) }})
* [Factory](https://fastify.dev/docs/v5.3.x/Reference/Server/#factory)
* [`http`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http)
* [`http2`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2)
* [`https`](https://fastify.dev/docs/v5.3.x/Reference/Server/#https)
* [`connectionTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#connectiontimeout)
* [`keepAliveTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#keepalivetimeout)
* [`forceCloseConnections`](https://fastify.dev/docs/v5.3.x/Reference/Server/#forcecloseconnections)
* [`maxRequestsPerSocket`](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxrequestspersocket)
* [`requestTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requesttimeout)
* [`ignoreTrailingSlash`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoretrailingslash)
* [`ignoreDuplicateSlashes`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ignoreduplicateslashes)
* [`maxParamLength`](https://fastify.dev/docs/v5.3.x/Reference/Server/#maxparamlength)
* [`bodyLimit`](https://fastify.dev/docs/v5.3.x/Reference/Server/#bodylimit)
* [`onProtoPoisoning`](https://fastify.dev/docs/v5.3.x/Reference/Server/#onprotopoisoning)
* [`onConstructorPoisoning`](https://fastify.dev/docs/v5.3.x/Reference/Server/#onconstructorpoisoning)
* [`logger`](https://fastify.dev/docs/v5.3.x/Reference/Server/#logger)
* [`loggerInstance`](https://fastify.dev/docs/v5.3.x/Reference/Server/#loggerinstance)
* [`disableRequestLogging`](https://fastify.dev/docs/v5.3.x/Reference/Server/#disablerequestlogging)
* [`serverFactory`](https://fastify.dev/docs/v5.3.x/Reference/Server/#serverfactory)
* [`caseSensitive`](https://fastify.dev/docs/v5.3.x/Reference/Server/#casesensitive)
* [`allowUnsafeRegex`](https://fastify.dev/docs/v5.3.x/Reference/Server/#allowunsaferegex)
* [`requestIdHeader`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidheader)
* [`requestIdLogLabel`](https://fastify.dev/docs/v5.3.x/Reference/Server/#requestidloglabel)
* [`genReqId`](https://fastify.dev/docs/v5.3.x/Reference/Server/#genreqid)
* [`trustProxy`](https://fastify.dev/docs/v5.3.x/Reference/Server/#trustproxy)
* [`pluginTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#plugintimeout)
* [`querystringParser`](https://fastify.dev/docs/v5.3.x/Reference/Server/#querystringparser)
* [`exposeHeadRoutes`](https://fastify.dev/docs/v5.3.x/Reference/Server/#exposeheadroutes)
* [`constraints`](https://fastify.dev/docs/v5.3.x/Reference/Server/#constraints)
* [`return503OnClosing`](https://fastify.dev/docs/v5.3.x/Reference/Server/#return503onclosing)
* [`ajv`](https://fastify.dev/docs/v5.3.x/Reference/Server/#ajv)
* [`serializerOpts`](https://fastify.dev/docs/v5.3.x/Reference/Server/#serializeropts)
* [`http2SessionTimeout`](https://fastify.dev/docs/v5.3.x/Reference/Server/#http2sessiontimeout)
* [`frameworkErrors`](https://fastify.dev/docs/v5.3.x/Reference/Server/#frameworkerrors)
* [`clientErrorHandler`](https://fastify.dev/docs/v5.3.x/Reference/Server/#clienterrorhandler)
* [`rewriteUrl`](https://fastify.dev/docs/v5.3.x/Reference/Server/#rewriteurl)
* [`useSemicolonDelimiter`](https://fastify.dev/docs/v5.3.x/Reference/Server/#usesemicolondelimiter)
* [Instance](https://fastify.dev/docs/v5.3.x/Reference/Server/#instance)
* [Server Methods](https://fastify.dev/docs/v5.3.x/Reference/Server/#server-methods)
* [`listenTextResolver`](https://fastify.dev/docs/v5.3.x/Reference/Server/#listentextresolver)
* [listeningOrigin](https://fastify.dev/docs/v5.3.x/Reference/Server/#listeningorigin)
---
# ContentTypeParser | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/ContentTypeParser/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
`Content-Type` Parser[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#content-type-parser "Direct link to content-type-parser")
------------------------------------------------------------------------------------------------------------------------------------------------
Fastify natively supports `'application/json'` and `'text/plain'` content types with a default charset of `utf-8`. These default parsers can be changed or removed.
Unsupported content types will throw an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error.
To support other content types, use the `addContentTypeParser` API or an existing [plugin](https://fastify.dev/ecosystem/)
.
As with other APIs, `addContentTypeParser` is encapsulated in the scope in which it is declared. If declared in the root scope, it is available everywhere; if declared in a plugin, it is available only in that scope and its children.
Fastify automatically adds the parsed request payload to the [Fastify request](https://fastify.dev/docs/v5.2.x/Reference/Request/)
object, accessible via `request.body`.
Note that for `GET` and `HEAD` requests, the payload is never parsed. For `OPTIONS` and `DELETE` requests, the payload is parsed only if a valid `content-type` header is provided. Unlike `POST`, `PUT`, and `PATCH`, the [catch-all](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#catch-all)
parser is not executed, and the payload is simply not parsed.
> ⚠ Warning: When using regular expressions to detect `Content-Type`, it is important to ensure proper detection. For example, to match `application/*`, use `/^application\/([\w-]+);?/` to match the [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#usage "Direct link to Usage")
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) })})// Handle multiple content types with the same functionfastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Async is also supported in Node versions >= 8.0.0fastify.addContentTypeParser('application/jsoff', async function (request, payload) { const res = await jsoffParserAsync(payload) return res})// Handle all content types that matches RegExpfastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) { imageParser(payload, function (err, body) { done(err, body) })})// Can use default JSON/Text parser for different content Typesfastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
Fastify first tries to match a content-type parser with a `string` value before trying to find a matching `RegExp`. For overlapping content types, it starts with the last one configured and ends with the first (last in, first out). To specify a general content type more precisely, first specify the general type, then the specific one, as shown below.
// Here only the second content type parser is called because its value also matches the first onefastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )// Here the desired behavior is achieved because fastify first tries to match the// `application/vnd.custom+xml` content type parserfastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
### Using addContentTypeParser with fastify.register[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister "Direct link to Using addContentTypeParser with fastify.register")
When using `addContentTypeParser` with `fastify.register`, avoid `await` when registering routes. Using `await` makes route registration asynchronous, potentially registering routes before `addContentTypeParser` is set.
#### Correct Usage[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#correct-usage "Direct link to Correct Usage")
const fastify = require('fastify')();fastify.register((fastify, opts) => { fastify.addContentTypeParser('application/json', function (request, payload, done) { jsonParser(payload, function (err, body) { done(err, body) }) }) fastify.get('/hello', async (req, res) => {});});
In addition to `addContentTypeParser`, the `hasContentTypeParser`, `removeContentTypeParser`, and `removeAllContentTypeParsers` APIs are available.
#### hasContentTypeParser[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#hascontenttypeparser "Direct link to hasContentTypeParser")
Use the `hasContentTypeParser` API to check if a specific content type parser exists.
if (!fastify.hasContentTypeParser('application/jsoff')){ fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) }) })}
#### removeContentTypeParser[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#removecontenttypeparser "Direct link to removeContentTypeParser")
`removeContentTypeParser` can remove a single content type or an array of content types, supporting both `string` and `RegExp`.
fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Removes the both built-in content type parsers so that only the content type parser for text/html is availablefastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
The `removeAllContentTypeParsers` API removes all existing content type parsers eliminating the need to specify each one individually. This API supports encapsulation and is useful for registering a [catch-all content type parser](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#catch-all)
that should be executed for every content type, ignoring built-in parsers.
fastify.removeAllContentTypeParsers()fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})
> 🛈 Note: `function(req, done)` and `async function(req)` are still supported but deprecated.
#### Body Parser[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#body-parser "Direct link to Body Parser")
The request body can be parsed in two ways. First, add a custom content type parser and handle the request stream. Or second, use the `parseAs` option in the `addContentTypeParser` API, specifying `'string'` or `'buffer'`. Fastify will handle the stream, check the [maximum size](https://fastify.dev/docs/v5.2.x/Reference/Server/#factory-body-limit)
of the body, and the content length. If the limit is exceeded, the custom parser will not be invoked.
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) { try { const json = JSON.parse(body) done(null, json) } catch (err) { err.statusCode = 400 done(err, undefined) }})
See [`example/parser.js`](https://github.com/fastify/fastify/blob/main/examples/parser.js)
for an example.
##### Custom Parser Options[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#custom-parser-options "Direct link to Custom Parser Options")
* `parseAs` (string): `'string'` or `'buffer'` to designate how the incoming data should be collected. Default: `'buffer'`.
* `bodyLimit` (number): The maximum payload size, in bytes, that the custom parser will accept. Defaults to the global body limit passed to the [`Fastify factory function`](https://fastify.dev/docs/v5.2.x/Reference/Server/#bodylimit)
.
#### Catch-All[](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#catch-all "Direct link to Catch-All")
To catch all requests regardless of content type, use the `'*'` content type:
fastify.addContentTypeParser('*', function (request, payload, done) { let data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
All requests without a corresponding content type parser will be handled by this function.
This is also useful for piping the request stream. Define a content parser like:
fastify.addContentTypeParser('*', function (request, payload, done) { done()})
And then access the core HTTP request directly for piping:
app.post('/hello', (request, reply) => { reply.send(request.raw)})
Here is a complete example that logs incoming [json line](https://jsonlines.org/)
objects:
const split2 = require('split2')const pump = require('pump')fastify.addContentTypeParser('*', (request, payload, done) => { done(null, pump(payload, split2(JSON.parse)))})fastify.route({ method: 'POST', url: '/api/log/jsons', handler: (req, res) => { req.body.on('data', d => console.log(d)) // log every incoming object }})
For piping file uploads, check out [`@fastify/multipart`](https://github.com/fastify/fastify-multipart)
.
To execute the content type parser on all content types, call `removeAllContentTypeParsers` first.
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parserfastify.removeAllContentTypeParsers()fastify.addContentTypeParser('*', function (request, payload, done) { const data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
* [`Content-Type` Parser](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#content-type-parser)
* [Usage](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#usage)
* [Using addContentTypeParser with fastify.register](https://fastify.dev/docs/v5.2.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister)
---
# Decorators | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Decorators/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Decorators[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorators "Direct link to Decorators")
------------------------------------------------------------------------------------------------------------
The decorators API customizes core Fastify objects, such as the server instance and any request and reply objects used during the HTTP request lifecycle. It can attach any type of property to core objects, e.g., functions, plain objects, or native types.
This API is _synchronous_. Defining a decoration asynchronously could result in the Fastify instance booting before the decoration completes. To register an asynchronous decoration, use the `register` API with `fastify-plugin`. See the [Plugins](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
documentation for more details.
Decorating core objects with this API allows the underlying JavaScript engine to optimize the handling of server, request, and reply objects. This is accomplished by defining the shape of all such object instances before they are instantiated and used. As an example, the following is not recommended because it will change the shape of objects during their lifecycle:
// Bad example! Continue reading.// Attach a user property to the incoming request before the request// handler is invoked.fastify.addHook('preHandler', function (req, reply, done) { req.user = 'Bob Dylan' done()})// Use the attached user property in the request handler.fastify.get('/', function (req, reply) { reply.send(`Hello, ${req.user}`)})
The above example mutates the request object after instantiation, causing the JavaScript engine to deoptimize access. Using the decoration API avoids this deoptimization:
// Decorate request with a 'user' propertyfastify.decorateRequest('user', '')// Update our propertyfastify.addHook('preHandler', (req, reply, done) => { req.user = 'Bob Dylan' done()})// And finally access itfastify.get('/', (req, reply) => { reply.send(`Hello, ${req.user}!`)})
Keep the initial shape of a decorated field close to its future dynamic value. Initialize a decorator as `''` for strings and `null` for objects or functions. This works only with value types; reference types will throw an error during Fastify startup. See [decorateRequest](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorate-request)
and [JavaScript engine fundamentals: Shapes and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
for more information.
### Usage[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#usage "Direct link to Usage")
#### `decorate(name, value, [dependencies])`[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decoratename-value-dependencies "Direct link to decoratename-value-dependencies")
This method customizes the Fastify [server](https://fastify.dev/docs/v5.2.x/Reference/Server/)
instance.
For example, to attach a new method to the server instance:
fastify.decorate('utility', function () { // Something very useful})
Non-function values can also be attached to the server instance:
fastify.decorate('conf', { db: 'some.db', port: 3000})
To access decorated properties, use the name provided to the decoration API:
fastify.utility()console.log(fastify.conf.db)
The decorated [Fastify server](https://fastify.dev/docs/v5.2.x/Reference/Server/)
is bound to `this` in [route](https://fastify.dev/docs/v5.2.x/Reference/Routes/)
handlers:
fastify.decorate('db', new DbConnection())fastify.get('/', async function (request, reply) { // using return return { hello: await this.db.query('world') } // or // using reply.send() reply.send({ hello: await this.db.query('world') }) await reply})
The `dependencies` parameter is an optional list of decorators that the decorator being defined relies upon. This list contains the names of other decorators. In the following example, the "utility" decorator depends on the "greet" and "hi" decorators:
async function greetDecorator (fastify, opts) { fastify.decorate('greet', () => { return 'greet message' })}async function hiDecorator (fastify, opts) { fastify.decorate('hi', () => { return 'hi message' })}async function utilityDecorator (fastify, opts) { fastify.decorate('utility', () => { return `${fastify.greet()} | ${fastify.hi()}` })}fastify.register(fastifyPlugin(greetDecorator, { name: 'greet' }))fastify.register(fastifyPlugin(hiDecorator, { name: 'hi' }))fastify.register(fastifyPlugin(utilityDecorator, { dependencies: ['greet', 'hi'] }))fastify.get('/', function (req, reply) { // Response: {"hello":"greet message | hi message"} reply.send({ hello: fastify.utility() })})fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err})
Using an arrow function breaks the binding of `this` to the `FastifyInstance`.
If a dependency is not satisfied, the `decorate` method throws an exception. The dependency check occurs before the server instance boots, not during runtime.
#### `decorateReply(name, value, [dependencies])`[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decoratereplyname-value-dependencies "Direct link to decoratereplyname-value-dependencies")
This API adds new methods/properties to the core `Reply` object:
fastify.decorateReply('utility', function () { // Something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Reply` instance.
Using `decorateReply` will throw and error if used with a reference type:
// Don't do thisfastify.decorateReply('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
.
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateReply('foo') app.addHook('onRequest', async (req, reply) => { reply.foo = { bar: 42 } })}module.exports = fp(myPlugin)
See [`decorate`](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `decorateRequest(name, value, [dependencies])`[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decoraterequestname-value-dependencies "Direct link to decoraterequestname-value-dependencies")
As with [`decorateReply`](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorate-reply)
, this API adds new methods/properties to the core `Request` object:
fastify.decorateRequest('utility', function () { // something very useful})
Using an arrow function will break the binding of `this` to the Fastify `Request` instance.
Using `decorateRequest` will emit an error if used with a reference type:
// Don't do thisfastify.decorateRequest('foo', { bar: 'fizz'})
In this example, the object reference would be shared with all requests, and **any mutation will impact all requests, potentially creating security vulnerabilities or memory leaks**. Fastify blocks this.
To achieve proper encapsulation across requests configure a new value for each incoming request in the [`'onRequest'` hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
.
Example:
const fp = require('fastify-plugin')async function myPlugin (app) { app.decorateRequest('foo') app.addHook('onRequest', async (req, reply) => { req.foo = { bar: 42 } })}module.exports = fp(myPlugin)
The hook solution is more flexible and allows for more complex initialization because more logic can be added to the `onRequest` hook.
Another approach is to use the getter/setter pattern, but it requires 2 decorators:
fastify.decorateRequest('my_decorator_holder') // define the holderfastify.decorateRequest('user', { getter () { this.my_decorator_holder ??= {} // initialize the holder return this.my_decorator_holder }})fastify.get('/', async function (req, reply) { req.user.access = 'granted' // other code})
This ensures that the `user` property is always unique for each request.
See [`decorate`](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorate)
for information about the `dependencies` parameter.
#### `hasDecorator(name)`[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#hasdecoratorname "Direct link to hasdecoratorname")
Used to check for the existence of a server instance decoration:
fastify.hasDecorator('utility')
#### hasRequestDecorator[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#hasrequestdecorator "Direct link to hasRequestDecorator")
Used to check for the existence of a Request decoration:
fastify.hasRequestDecorator('utility')
#### hasReplyDecorator[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#hasreplydecorator "Direct link to hasReplyDecorator")
Used to check for the existence of a Reply decoration:
fastify.hasReplyDecorator('utility')
### Decorators and Encapsulation[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorators-and-encapsulation "Direct link to Decorators and Encapsulation")
Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`) with the same name more than once in the same **encapsulated** context will throw an exception. For example, the following will throw:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine})server.get('/', (req, reply) => { reply.view('/index.html', { hello: 'world' })})// Somewhere else in our codebase, we define another// view decorator. This throws.server.decorateReply('view', function (template, args) { // Another rendering engine})server.listen({ port: 3000 })
But this will not:
const server = require('fastify')()server.decorateReply('view', function (template, args) { // Amazing view rendering engine.})server.register(async function (server, opts) { // We add a view decorator to the current encapsulated // plugin. This will not throw as outside of this encapsulated // plugin view is the old one, while inside it is the new one. server.decorateReply('view', function (template, args) { // Another rendering engine }) server.get('/', (req, reply) => { reply.view('/index.page', { hello: 'world' }) })}, { prefix: '/bar' })server.listen({ port: 3000 })
### Getters and Setters[](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#getters-and-setters "Direct link to Getters and Setters")
Decorators accept special "getter/setter" objects with `getter` and optional `setter` functions. This allows defining properties via decorators, for example:
fastify.decorate('foo', { getter () { return 'a getter' }})
Will define the `foo` property on the Fastify instance:
console.log(fastify.foo) // 'a getter'
* [Decorators](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorators)
* [Usage](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#usage)
* [Decorators and Encapsulation](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#decorators-and-encapsulation)
* [Getters and Setters](https://fastify.dev/docs/v5.2.x/Reference/Decorators/#getters-and-setters)
---
# Encapsulation | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Encapsulation/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Encapsulation[](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/#encapsulation "Direct link to Encapsulation")
------------------------------------------------------------------------------------------------------------------------
A fundamental feature of Fastify is the "encapsulation context." It governs which [decorators](https://fastify.dev/docs/v5.2.x/Reference/Decorators/)
, registered [hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/)
, and [plugins](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
are available to [routes](https://fastify.dev/docs/v5.2.x/Reference/Routes/)
. A visual representation of the encapsulation context is shown in the following figure:

In the figure above, there are several entities:
1. The _root context_
2. Three _root plugins_
3. Two _child contexts_, each with:
* Two _child plugins_
* One _grandchild context_, each with:
* Three _child plugins_
Every _child context_ and _grandchild context_ has access to the _root plugins_. Within each _child context_, the _grandchild contexts_ have access to the _child plugins_ registered within the containing _child context_, but the containing _child context_ **does not** have access to the _child plugins_ registered within its _grandchild context_.
Given that everything in Fastify is a [plugin](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
except for the _root context_, every "context" and "plugin" in this example is a plugin that can consist of decorators, hooks, plugins, and routes. To put this example into concrete terms, consider a basic scenario of a REST API server with three routes: the first route (`/one`) requires authentication, the second route (`/two`) does not, and the third route (`/three`) has access to the same context as the second route. Using [@fastify/bearer-auth](https://github.com/fastify/fastify-bearer-auth)
to provide authentication, the code for this example is as follows:
'use strict'const fastify = require('fastify')()fastify.decorateRequest('answer', 42)fastify.register(async function authenticatedContext (childServer) { childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] }) childServer.route({ path: '/one', method: 'GET', handler (request, response) { response.send({ answer: request.answer, // request.foo will be undefined as it is only defined in publicContext foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } })})fastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, // request.bar will be undefined as it is only defined in grandchildContext bar: request.bar }) } }) childServer.register(async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) })})fastify.listen({ port: 8000 })
The server example above demonstrates the encapsulation concepts from the original diagram:
1. Each _child context_ (`authenticatedContext`, `publicContext`, and `grandchildContext`) has access to the `answer` request decorator defined in the _root context_.
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth` plugin.
3. Both the `publicContext` and `grandchildContext` have access to the `foo` request decorator.
4. Only the `grandchildContext` has access to the `bar` request decorator.
To see this, start the server and issue requests:
# curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one{"answer":42}# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
Sharing Between Contexts[](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/#sharing-between-contexts "Direct link to Sharing Between Contexts")
---------------------------------------------------------------------------------------------------------------------------------------------------------
Each context in the prior example inherits _only_ from its parent contexts. Parent contexts cannot access entities within their descendant contexts. If needed, encapsulation can be broken using [fastify-plugin](https://github.com/fastify/fastify-plugin)
, making anything registered in a descendant context available to the parent context.
To allow `publicContext` access to the `bar` decorator in `grandchildContext`, rewrite the code as follows:
'use strict'const fastify = require('fastify')()const fastifyPlugin = require('fastify-plugin')fastify.decorateRequest('answer', 42)// `authenticatedContext` omitted for clarityfastify.register(async function publicContext (childServer) { childServer.decorateRequest('foo', 'foo') childServer.route({ path: '/two', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) childServer.register(fastifyPlugin(grandchildContext)) async function grandchildContext (grandchildServer) { grandchildServer.decorateRequest('bar', 'bar') grandchildServer.route({ path: '/three', method: 'GET', handler (request, response) { response.send({ answer: request.answer, foo: request.foo, bar: request.bar }) } }) }})fastify.listen({ port: 8000 })
Restarting the server and re-issuing the requests for `/two` and `/three`:
# curl http://127.0.0.1:8000/two{"answer":42,"foo":"foo","bar":"bar"}# curl http://127.0.0.1:8000/three{"answer":42,"foo":"foo","bar":"bar"}
* [Encapsulation](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/#encapsulation)
* [Sharing Between Contexts](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/#sharing-between-contexts)
---
# Errors | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Errors/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Errors/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Errors[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors "Direct link to Errors")
--------------------------------------------------------------------------------------------
**Table of contents**
* [Errors](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.2.x/Reference/Errors/#error-handling-in-nodejs)
* [Uncaught Errors](https://fastify.dev/docs/v5.2.x/Reference/Errors/#uncaught-errors)
* [Catching Errors In Promises](https://fastify.dev/docs/v5.2.x/Reference/Errors/#catching-errors-in-promises)
* [Errors In Fastify](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify)
* [Errors In Input Data](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-input-data)
* [Catching Uncaught Errors In Fastify](https://fastify.dev/docs/v5.2.x/Reference/Errors/#catching-uncaught-errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fastify-error-codes)
* [FST\_ERR\_NOT\_FOUND](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_not_found)
* [FST\_ERR\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_options_not_obj)
* [FST\_ERR\_QSP\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_qsp_not_fn)
* [FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_schema_controller_bucket_opt_not_fn)
* [FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_schema_error_formatter_not_fn)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_obj)
* [FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ajv_custom_options_opt_not_arr)
* [FST\_ERR\_CTP\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_already_present)
* [FST\_ERR\_CTP\_INVALID\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_invalid_type)
* [FST\_ERR\_CTP\_EMPTY\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_empty_type)
* [FST\_ERR\_CTP\_INVALID\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_invalid_handler)
* [FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_invalid_parse_type)
* [FST\_ERR\_CTP\_BODY\_TOO\_LARGE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_body_too_large)
* [FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_invalid_media_type)
* [FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_invalid_content_length)
* [FST\_ERR\_CTP\_EMPTY\_JSON\_BODY](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_empty_json_body)
* [FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_ctp_instance_already_started)
* [FST\_ERR\_INSTANCE\_ALREADY\_LISTENING](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_instance_already_listening)
* [FST\_ERR\_DEC\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_dec_already_present)
* [FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_dec_dependency_invalid_type)
* [FST\_ERR\_DEC\_MISSING\_DEPENDENCY](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_dec_missing_dependency)
* [FST\_ERR\_DEC\_AFTER\_START](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_dec_after_start)
* [FST\_ERR\_DEC\_REFERENCE\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_dec_reference_type)
* [FST\_ERR\_HOOK\_INVALID\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_hook_invalid_type)
* [FST\_ERR\_HOOK\_INVALID\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_hook_invalid_handler)
* [FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_hook_invalid_async_handler)
* [FST\_ERR\_HOOK\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_hook_not_supported)
* [FST\_ERR\_MISSING\_MIDDLEWARE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_missing_middleware)
* [FST\_ERR\_HOOK\_TIMEOUT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_hook_timeout)
* [FST\_ERR\_LOG\_INVALID\_DESTINATION](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_log_invalid_destination)
* [FST\_ERR\_LOG\_INVALID\_LOGGER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_log_invalid_logger)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_log_invalid_logger_instance)
* [FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_log_invalid_logger_config)
* [FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_log_logger_and_logger_instance_provided)
* [FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_rep_invalid_payload_type)
* [FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_rep_response_body_consumed)
* [FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_rep_readable_stream_locked)
* [FST\_ERR\_REP\_ALREADY\_SENT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_rep_already_sent)
* [FST\_ERR\_REP\_SENT\_VALUE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_rep_sent_value)
* [FST\_ERR\_SEND\_INSIDE\_ONERR](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_send_inside_onerr)
* [FST\_ERR\_SEND\_UNDEFINED\_ERR](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_send_undefined_err)
* [FST\_ERR\_BAD\_STATUS\_CODE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_bad_status_code)
* [FST\_ERR\_BAD\_TRAILER\_NAME](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_bad_trailer_name)
* [FST\_ERR\_BAD\_TRAILER\_VALUE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_bad_trailer_value)
* [FST\_ERR\_FAILED\_ERROR\_SERIALIZATION](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_failed_error_serialization)
* [FST\_ERR\_MISSING\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_missing_serialization_fn)
* [FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_missing_contenttype_serialization_fn)
* [FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_req_invalid_validation_invocation)
* [FST\_ERR\_SCH\_MISSING\_ID](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_missing_id)
* [FST\_ERR\_SCH\_ALREADY\_PRESENT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_already_present)
* [FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_content_missing_schema)
* [FST\_ERR\_SCH\_DUPLICATE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_duplicate)
* [FST\_ERR\_SCH\_VALIDATION\_BUILD](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_validation_build)
* [FST\_ERR\_SCH\_SERIALIZATION\_BUILD](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_serialization_build)
* [FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_sch_response_schema_not_nested_2xx)
* [FST\_ERR\_HTTP2\_INVALID\_VERSION](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_http2_invalid_version)
* [FST\_ERR\_INIT\_OPTS\_INVALID](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_init_opts_invalid)
* [FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_force_close_connections_idle_not_available)
* [FST\_ERR\_DUPLICATED\_ROUTE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_duplicated_route)
* [FST\_ERR\_BAD\_URL](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_bad_url)
* [FST\_ERR\_ASYNC\_CONSTRAINT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_async_constraint)
* [FST\_ERR\_INVALID\_URL](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_invalid_url)
* [FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_options_not_obj)
* [FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_duplicated_handler)
* [FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_handler_not_fn)
* [FST\_ERR\_ROUTE\_MISSING\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_missing_handler)
* [FST\_ERR\_ROUTE\_METHOD\_INVALID](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_method_invalid)
* [FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_method_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_body_validation_schema_not_supported)
* [FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_body_limit_option_not_int)
* [FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_route_rewrite_not_str)
* [FST\_ERR\_REOPENED\_CLOSE\_SERVER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_reopened_close_server)
* [FST\_ERR\_REOPENED\_SERVER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_reopened_server)
* [FST\_ERR\_PLUGIN\_VERSION\_MISMATCH](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_version_mismatch)
* [FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_callback_not_fn)
* [FST\_ERR\_PLUGIN\_NOT\_VALID](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_not_valid)
* [FST\_ERR\_ROOT\_PLG\_BOOTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_root_plg_booted)
* [FST\_ERR\_PARENT\_PLUGIN\_BOOTED](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_parent_plugin_booted)
* [FST\_ERR\_PLUGIN\_TIMEOUT](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_timeout)
* [FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_not_present_in_instance)
* [FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_plugin_invalid_async_handler)
* [FST\_ERR\_VALIDATION](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_validation)
* [FST\_ERR\_LISTEN\_OPTIONS\_INVALID](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_listen_options_invalid)
* [FST\_ERR\_ERROR\_HANDLER\_NOT\_FN](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fst_err_error_handler_not_fn)
### Error Handling In Node.js[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#error-handling-in-nodejs "Direct link to Error Handling In Node.js")
#### Uncaught Errors[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#uncaught-errors "Direct link to Uncaught Errors")
In Node.js, uncaught errors can cause memory leaks, file descriptor leaks, and other major production issues. [Domains](https://nodejs.org/en/docs/guides/domain-postmortem/)
were a failed attempt to fix this.
Given that it is not possible to process all uncaught errors sensibly, the best way to deal with them is to [crash](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly)
.
#### Catching Errors In Promises[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#catching-errors-in-promises "Direct link to Catching Errors In Promises")
When using promises, attach a `.catch()` handler synchronously.
### Errors In Fastify[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify "Direct link to Errors In Fastify")
Fastify follows an all-or-nothing approach and aims to be lean and optimal. The developer is responsible for ensuring errors are handled properly.
#### Errors In Input Data[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-input-data "Direct link to Errors In Input Data")
Most errors result from unexpected input data, so it is recommended to [validate input data against a JSON schema](https://fastify.dev/docs/v5.2.x/Reference/Validation-and-Serialization/)
.
#### Catching Uncaught Errors In Fastify[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#catching-uncaught-errors-in-fastify "Direct link to Catching Uncaught Errors In Fastify")
Fastify tries to catch as many uncaught errors as possible without hindering performance. This includes:
1. synchronous routes, e.g. `app.get('/', () => { throw new Error('kaboom') })`
2. `async` routes, e.g. `app.get('/', async () => { throw new Error('kaboom') })`
In both cases, the error will be caught safely and routed to Fastify's default error handler, resulting in a generic `500 Internal Server Error` response.
To customize this behavior, use [`setErrorHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#seterrorhandler)
.
### Errors In Fastify Lifecycle Hooks And A Custom Error Handler[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler "Direct link to Errors In Fastify Lifecycle Hooks And A Custom Error Handler")
From the [Hooks documentation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#manage-errors-from-a-hook)
:
> If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
When a custom error handler is defined through [`setErrorHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#seterrorhandler)
, it will receive the error passed to the `done()` callback or through other supported automatic error handling mechanisms. If `setErrorHandler` is used multiple times, the error will be routed to the most precedent handler within the error [encapsulation context](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/)
. Error handlers are fully encapsulated, so a `setErrorHandler` call within a plugin will limit the error handler to that plugin's context.
The root error handler is Fastify's generic error handler. This error handler will use the headers and status code in the `Error` object, if they exist. The headers and status code will not be automatically set if a custom error handler is provided.
The following should be considered when using a custom error handler:
* `reply.send(data)` behaves as in [regular route handlers](https://fastify.dev/docs/v5.2.x/Reference/Reply/#senddata)
* objects are serialized, triggering the `preSerialization` lifecycle hook if defined
* strings, buffers, and streams are sent to the client with appropriate headers (no serialization)
* Throwing a new error in a custom error handler will call the parent `errorHandler`.
* The `onError` hook will be triggered once for the first error thrown
* An error will not be triggered twice from a lifecycle hook. Fastify internally monitors error invocation to avoid infinite loops for errors thrown in the reply phases of the lifecycle (those after the route handler)
When using Fastify's custom error handling through [`setErrorHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#seterrorhandler)
, be aware of how errors are propagated between custom and default error handlers.
If a plugin's error handler re-throws an error that is not an instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
, it will not propagate to the parent context error handler. Instead, it will be caught by the default error handler. This can be seen in the `/bad` route of the example below.
To ensure consistent error handling, throw instances of `Error`. For example, replace `throw 'foo'` with `throw new Error('foo')` in the `/bad` route to ensure errors propagate through the custom error handling chain as intended. This practice helps avoid potential pitfalls when working with custom error handling in Fastify.
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Register parent error handlerfastify.setErrorHandler((error, request, reply) => { reply.status(500).send({ ok: false })})fastify.register((app, options, next) => { // Register child error handler fastify.setErrorHandler((error, request, reply) => { throw error }) fastify.get('/bad', async () => { // Throws a non-Error type, 'bar' throw 'foo' }) fastify.get('/good', async () => { // Throws an Error instance, 'bar' throw new Error('bar') }) next()})// Run the serverfastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is listening at ${address}})
### Fastify Error Codes[](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fastify-error-codes "Direct link to Fastify Error Codes")
You can access `errorCodes` for mapping:
// ESMimport { errorCodes } from 'fastify'// CommonJSconst errorCodes = require('fastify').errorCodes
For example:
const Fastify = require('fastify')// Instantiate the frameworkconst fastify = Fastify({ logger: true})// Declare a routefastify.get('/', function (request, reply) { reply.code('bad status code').send({ hello: 'world' })})fastify.setErrorHandler(function (error, request, reply) { if (error instanceof Fastify.errorCodes.FST_ERR_BAD_STATUS_CODE) { // Log error this.log.error(error) // Send error response reply.status(500).send({ ok: false }) } else { // Fastify will use parent error handler to handle this reply.send(error) }})// Run the server!fastify.listen({ port: 3000 }, function (err, address) { if (err) { fastify.log.error(err) process.exit(1) } // Server is now listening on ${address}})
Below is a table with all the error codes used by Fastify.
| Code | Description | How to solve | Discussion |
| --- | --- | --- | --- |
| FST\_ERR\_NOT\_FOUND | 404 Not Found | \- | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_OPTIONS\_NOT\_OBJ | Fastify options wrongly specified. | Fastify options should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_QSP\_NOT\_FN | QueryStringParser wrongly specified. | QueryStringParser option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_CONTROLLER\_BUCKET\_OPT\_NOT\_FN | SchemaController.bucket wrongly specified. | SchemaController.bucket option should be a function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_SCHEMA\_ERROR\_FORMATTER\_NOT\_FN | SchemaErrorFormatter option wrongly specified. | SchemaErrorFormatter option should be a non async function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_OBJ | ajv.customOptions wrongly specified. | ajv.customOptions option should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_AJV\_CUSTOM\_OPTIONS\_OPT\_NOT\_ARR | ajv.plugins option wrongly specified. | ajv.plugins option should be an array. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_CTP\_ALREADY\_PRESENT | The parser for this content type was already registered. | Use a different content type or delete the already registered parser. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_TYPE | `Content-Type` wrongly specified | The `Content-Type` should be a string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_TYPE | `Content-Type` is an empty string. | `Content-Type` cannot be an empty string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_HANDLER | Invalid handler for the content type. | Use a different handler. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_PARSE\_TYPE | The provided parse type is not supported. | Accepted values are `string` or `buffer`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_BODY\_TOO\_LARGE | The request body is larger than the provided limit. | Increase the limit in the Fastify server instance setting: [bodyLimit](https://fastify.dev/docs/v5.2.x/Reference/Server/#bodylimit) | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_MEDIA\_TYPE | The received media type is not supported (i.e. there is no suitable `Content-Type` parser for it). | Use a different content type. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_INVALID\_CONTENT\_LENGTH | Request body size did not match `Content-Length`. | Check the request body size and the `Content-Length` header. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_CTP\_EMPTY\_JSON\_BODY | Body cannot be empty when content-type is set to `application/json`. | Check the request body. | [#1253](https://github.com/fastify/fastify/pull/1253) |
| FST\_ERR\_CTP\_INSTANCE\_ALREADY\_STARTED | Fastify is already started. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_INSTANCE\_ALREADY\_LISTENING | Fastify instance is already listening. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_DEC\_ALREADY\_PRESENT | A decorator with the same name is already registered. | Use a different decorator name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_DEPENDENCY\_INVALID\_TYPE | The dependencies of decorator must be of type `Array`. | Use an array for the dependencies. | [#3090](https://github.com/fastify/fastify/pull/3090) |
| FST\_ERR\_DEC\_MISSING\_DEPENDENCY | The decorator cannot be registered due to a missing dependency. | Register the missing dependency. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_DEC\_AFTER\_START | The decorator cannot be added after start. | Add the decorator before starting the server. | [#2128](https://github.com/fastify/fastify/pull/2128) |
| FST\_ERR\_DEC\_REFERENCE\_TYPE | The decorator cannot be a reference type. | Define the decorator with a getter/setter interface or an empty decorator with a hook. | [#5462](https://github.com/fastify/fastify/pull/5462) |
| FST\_ERR\_HOOK\_INVALID\_TYPE | The hook name must be a string. | Use a string for the hook name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_HANDLER | The hook callback must be a function. | Use a function for the hook callback. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_HOOK\_INVALID\_ASYNC\_HANDLER | Async function has too many arguments. Async hooks should not use the `done` argument. | Remove the `done` argument from the async hook. | [#4367](https://github.com/fastify/fastify/pull/4367) |
| FST\_ERR\_HOOK\_NOT\_SUPPORTED | The hook is not supported. | Use a supported hook. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_MISSING\_MIDDLEWARE | You must register a plugin for handling middlewares, visit [`Middleware`](https://fastify.dev/docs/v5.2.x/Reference/Middleware/)
for more info. | Register a plugin for handling middlewares. | [#2014](https://github.com/fastify/fastify/pull/2014) |
| FST\_ERR\_HOOK\_TIMEOUT | A callback for a hook timed out. | Increase the timeout for the hook. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_LOG\_INVALID\_DESTINATION | The logger does not accept the specified destination. | Use a `'stream'` or a `'file'` as the destination. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_LOG\_INVALID\_LOGGER | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_INSTANCE | The `loggerInstance` only accepts a logger instance, not a configuration object. | To pass a configuration object, use `'logger'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_INVALID\_LOGGER\_CONFIG | The logger option only accepts a configuration object, not a logger instance. | To pass an instance, use `'loggerInstance'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_LOG\_LOGGER\_AND\_LOGGER\_INSTANCE\_PROVIDED | You cannot provide both `'logger'` and `'loggerInstance'`. | Please provide only one option. | [#5020](https://github.com/fastify/fastify/pull/5020) |
| FST\_ERR\_REP\_INVALID\_PAYLOAD\_TYPE | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_REP\_RESPONSE\_BODY\_CONSUMED | Using `Response` as reply payload, but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |
| FST\_ERR\_REP\_READABLE\_STREAM\_LOCKED | Using `ReadableStream` as reply payload, but locked with another reader. | Make sure you don't call the `Readable.getReader` before sending or release lock with `reader.releaseLock()` before sending. | [#5920](https://github.com/fastify/fastify/pull/5920) |
| FST\_ERR\_REP\_ALREADY\_SENT | A response was already sent. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_REP\_SENT\_VALUE | The only possible value for `reply.sent` is `true`. | \- | [#1336](https://github.com/fastify/fastify/pull/1336) |
| FST\_ERR\_SEND\_INSIDE\_ONERR | You cannot use `send` inside the `onError` hook. | \- | [#1348](https://github.com/fastify/fastify/pull/1348) |
| FST\_ERR\_SEND\_UNDEFINED\_ERR | Undefined error has occurred. | \- | [#2074](https://github.com/fastify/fastify/pull/2074) |
| FST\_ERR\_BAD\_STATUS\_CODE | The status code is not valid. | Use a valid status code. | [#2082](https://github.com/fastify/fastify/pull/2082) |
| FST\_ERR\_BAD\_TRAILER\_NAME | Called `reply.trailer` with an invalid header name. | Use a valid header name. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_BAD\_TRAILER\_VALUE | Called `reply.trailer` with an invalid type. Expected a function. | Use a function. | [#3794](https://github.com/fastify/fastify/pull/3794) |
| FST\_ERR\_FAILED\_ERROR\_SERIALIZATION | Failed to serialize an error. | \- | [#4601](https://github.com/fastify/fastify/pull/4601) |
| FST\_ERR\_MISSING\_SERIALIZATION\_FN | Missing serialization function. | Add a serialization function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_MISSING\_CONTENTTYPE\_SERIALIZATION\_FN | Missing `Content-Type` serialization function. | Add a serialization function. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_REQ\_INVALID\_VALIDATION\_INVOCATION | Invalid validation invocation. Missing validation function for HTTP part nor schema provided. | Add a validation function. | [#3970](https://github.com/fastify/fastify/pull/3970) |
| FST\_ERR\_SCH\_MISSING\_ID | The schema provided does not have `$id` property. | Add a `$id` property. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_ALREADY\_PRESENT | A schema with the same `$id` already exists. | Use a different `$id`. | [#1168](https://github.com/fastify/fastify/pull/1168) |
| FST\_ERR\_SCH\_CONTENT\_MISSING\_SCHEMA | A schema is missing for the corresponding content type. | Add a schema. | [#4264](https://github.com/fastify/fastify/pull/4264) |
| FST\_ERR\_SCH\_DUPLICATE | Schema with the same attribute already present! | Use a different attribute. | [#1954](https://github.com/fastify/fastify/pull/1954) |
| FST\_ERR\_SCH\_VALIDATION\_BUILD | The JSON schema provided for validation to a route is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_SERIALIZATION\_BUILD | The JSON schema provided for serialization of a route response is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
| FST\_ERR\_SCH\_RESPONSE\_SCHEMA\_NOT\_NESTED\_2XX | Response schemas should be nested under a valid status code (2XX). | Use a valid status code. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_HTTP2\_INVALID\_VERSION | HTTP2 is available only from node >= 8.8.1. | Use a higher version of node. | [#1346](https://github.com/fastify/fastify/pull/1346) |
| FST\_ERR\_INIT\_OPTS\_INVALID | Invalid initialization options. | Use valid initialization options. | [#1471](https://github.com/fastify/fastify/pull/1471) |
| FST\_ERR\_FORCE\_CLOSE\_CONNECTIONS\_IDLE\_NOT\_AVAILABLE | Cannot set forceCloseConnections to `idle` as your HTTP server does not support `closeIdleConnections` method. | Use a different value for `forceCloseConnections`. | [#3925](https://github.com/fastify/fastify/pull/3925) |
| FST\_ERR\_DUPLICATED\_ROUTE | The HTTP method already has a registered controller for that URL. | Use a different URL or register the controller for another HTTP method. | [#2954](https://github.com/fastify/fastify/pull/2954) |
| FST\_ERR\_BAD\_URL | The router received an invalid URL. | Use a valid URL. | [#2106](https://github.com/fastify/fastify/pull/2106) |
| FST\_ERR\_ASYNC\_CONSTRAINT | The router received an error when using asynchronous constraints. | \- | [#4323](https://github.com/fastify/fastify/pull/4323) |
| FST\_ERR\_INVALID\_URL | URL must be a string. | Use a string for the URL. | [#3653](https://github.com/fastify/fastify/pull/3653) |
| FST\_ERR\_ROUTE\_OPTIONS\_NOT\_OBJ | Options for the route must be an object. | Use an object for the route options. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_DUPLICATED\_HANDLER | Duplicate handler for the route is not allowed. | Use a different handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_HANDLER\_NOT\_FN | Handler for the route must be a function. | Use a function for the handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_MISSING\_HANDLER | Missing handler function for the route. | Add a handler function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_METHOD\_INVALID | Method is not a valid value. | Use a valid value for the method. | [#4750](https://github.com/fastify/fastify/pull/4750) |
| FST\_ERR\_ROUTE\_METHOD\_NOT\_SUPPORTED | Method is not supported for the route. | Use a supported method. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_VALIDATION\_SCHEMA\_NOT\_SUPPORTED | Body validation schema route is not supported. | Use a different different method for the route. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_BODY\_LIMIT\_OPTION\_NOT\_INT | `bodyLimit` option must be an integer. | Use an integer for the `bodyLimit` option. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_ROUTE\_REWRITE\_NOT\_STR | `rewriteUrl` needs to be of type `string`. | Use a string for the `rewriteUrl`. | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_REOPENED\_CLOSE\_SERVER | Fastify has already been closed and cannot be reopened. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_REOPENED\_SERVER | Fastify is already listening. | \- | [#2415](https://github.com/fastify/fastify/pull/2415) |
| FST\_ERR\_PLUGIN\_VERSION\_MISMATCH | Installed Fastify plugin mismatched expected version. | Use a compatible version of the plugin. | [#2549](https://github.com/fastify/fastify/pull/2549) |
| FST\_ERR\_PLUGIN\_CALLBACK\_NOT\_FN | Callback for a hook is not a function. | Use a function for the callback. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_VALID | Plugin must be a function or a promise. | Use a function or a promise for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_ROOT\_PLG\_BOOTED | Root plugin has already booted. | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PARENT\_PLUGIN\_BOOTED | Impossible to load plugin because the parent (mapped directly from `avvio`) | \- | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_TIMEOUT | Plugin did not start in time. | Increase the timeout for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
| FST\_ERR\_PLUGIN\_NOT\_PRESENT\_IN\_INSTANCE | The decorator is not present in the instance. | \- | [#4554](https://github.com/fastify/fastify/pull/4554) |
| FST\_ERR\_PLUGIN\_INVALID\_ASYNC\_HANDLER | The plugin being registered mixes async and callback styles. | \- | [#5141](https://github.com/fastify/fastify/pull/5141) |
| FST\_ERR\_VALIDATION | The Request failed the payload validation. | Check the request payload. | [#4824](https://github.com/fastify/fastify/pull/4824) |
| FST\_ERR\_LISTEN\_OPTIONS\_INVALID | Invalid listen options. | Check the listen options. | [#4886](https://github.com/fastify/fastify/pull/4886) |
| FST\_ERR\_ERROR\_HANDLER\_NOT\_FN | Error Handler must be a function | Provide a function to `setErrorHandler`. | [#5317](https://github.com/fastify/fastify/pull/5317) |
* [Errors](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors)
* [Error Handling In Node.js](https://fastify.dev/docs/v5.2.x/Reference/Errors/#error-handling-in-nodejs)
* [Errors In Fastify](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify)
* [Errors In Fastify Lifecycle Hooks And A Custom Error Handler](https://fastify.dev/docs/v5.2.x/Reference/Errors/#errors-in-fastify-lifecycle-hooks-and-a-custom-error-handler)
* [Fastify Error Codes](https://fastify.dev/docs/v5.2.x/Reference/Errors/#fastify-error-codes)
---
# HTTP2 | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/HTTP2/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
HTTP2[](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#http2 "Direct link to HTTP2")
----------------------------------------------------------------------------------------
_Fastify_ supports HTTP2 over HTTPS (h2) or plaintext (h2c).
Currently, none of the HTTP2-specific APIs are available through _Fastify_, but Node's `req` and `res` can be accessed through the `Request` and `Reply` interfaces. PRs are welcome.
### Secure (HTTPS)[](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#secure-https "Direct link to Secure (HTTPS)")
HTTP2 is supported in all modern browsers **only over a secure connection**:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
[ALPN negotiation](https://datatracker.ietf.org/doc/html/rfc7301)
allows support for both HTTPS and HTTP/2 over the same socket. Node core `req` and `res` objects can be either [HTTP/1](https://nodejs.org/api/http.html)
or [HTTP/2](https://nodejs.org/api/http2.html)
. _Fastify_ supports this out of the box:
'use strict'const fs = require('node:fs')const path = require('node:path')const fastify = require('fastify')({ http2: true, https: { allowHTTP1: true, // fallback support for HTTP1 key: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.key')), cert: fs.readFileSync(path.join(__dirname, '..', 'https', 'fastify.cert')) }})// this route can be accessed through both protocolsfastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url https://localhost:3000
### Plain or insecure[](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#plain-or-insecure "Direct link to Plain or insecure")
For microservices, HTTP2 can connect in plain text, but this is not supported by browsers.
'use strict'const fastify = require('fastify')({ http2: true})fastify.get('/', function (request, reply) { reply.code(200).send({ hello: 'world' })})fastify.listen({ port: 3000 })
Test the new server with:
$ npx h2url http://localhost:3000
* [HTTP2](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#http2)
* [Secure (HTTPS)](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#secure-https)
* [Plain or insecure](https://fastify.dev/docs/v5.2.x/Reference/HTTP2/#plain-or-insecure)
---
# Hooks | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Hooks/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Hooks[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#hooks "Direct link to Hooks")
----------------------------------------------------------------------------------------
Hooks are registered with the `fastify.addHook` method and allow you to listen to specific events in the application or request/response lifecycle. You have to register a hook before the event is triggered, otherwise, the event is lost.
By using hooks you can interact directly with the lifecycle of Fastify. There are Request/Reply hooks and application hooks:
* [Request/Reply Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#diagnostics-channel-hooks)
> 🛈 Note: The `done` callback is not available when using `async`/`await` or returning a `Promise`. If you do invoke a `done` callback in this situation unexpected behavior may occur, e.g. duplicate invocation of handlers.
Request/Reply Hooks[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#requestreply-hooks "Direct link to Request/Reply Hooks")
---------------------------------------------------------------------------------------------------------------------------------
[Request](https://fastify.dev/docs/v5.2.x/Reference/Request/)
and [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/)
are the core Fastify objects.
`done` is the function to continue with the [lifecycle](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/)
.
It is easy to understand where each hook is executed by looking at the [lifecycle page](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/)
.
Hooks are affected by Fastify's encapsulation, and can thus be applied to selected routes. See the [Scopes](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#scope)
section for more information.
There are eight different hooks that you can use in Request/Reply _(in order of execution)_:
### onRequest[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest "Direct link to onRequest")
fastify.addHook('onRequest', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequest', async (request, reply) => { // Some code await asyncMethod()})
> 🛈 Note: In the [onRequest](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
> hook.
### preParsing[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing "Direct link to preParsing")
If you are using the `preParsing` hook, you can transform the request payload stream before it is parsed. It receives the request and reply objects as other hooks, and a stream with the current request payload.
If it returns a value (via `return` or via the callback function), it must return a stream.
For instance, you can decompress the request body:
fastify.addHook('preParsing', (request, reply, payload, done) => { // Some code done(null, newPayload)})
Or `async/await`:
fastify.addHook('preParsing', async (request, reply, payload) => { // Some code await asyncMethod() return newPayload})
> 🛈 Note: In the [preParsing](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing)
> hook, `request.body` will always be `undefined`, because the body parsing happens before the [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
> hook.
> 🛈 Note: You should also add a `receivedEncodedLength` property to the returned stream. This property is used to correctly match the request payload with the `Content-Length` header value. Ideally, this property should be updated on each received chunk.
> 🛈 Note: The size of the returned stream is checked to not exceed the limit set in [`bodyLimit`](https://fastify.dev/docs/v5.2.x/Reference/Server/#bodylimit)
> option.
### preValidation[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation "Direct link to preValidation")
If you are using the `preValidation` hook, you can change the payload before it is validated. For example:
fastify.addHook('preValidation', (request, reply, done) => { request.body = { ...request.body, importantKey: 'randomString' } done()})
Or `async/await`:
fastify.addHook('preValidation', async (request, reply) => { const importantKey = await generateRandomString() request.body = { ...request.body, importantKey }})
### preHandler[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prehandler "Direct link to preHandler")
The `preHandler` hook allows you to specify a function that is executed before a routes's handler.
fastify.addHook('preHandler', (request, reply, done) => { // some code done()})
Or `async/await`:
fastify.addHook('preHandler', async (request, reply) => { // Some code await asyncMethod()})
### preSerialization[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preserialization "Direct link to preSerialization")
If you are using the `preSerialization` hook, you can change (or replace) the payload before it is serialized. For example:
fastify.addHook('preSerialization', (request, reply, payload, done) => { const err = null const newPayload = { wrapped: payload } done(err, newPayload)})
Or `async/await`:
fastify.addHook('preSerialization', async (request, reply, payload) => { return { wrapped: payload }})
> 🛈 Note: The hook is NOT called if the payload is a `string`, a `Buffer`, a `stream`, or `null`.
### onError[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onerror "Direct link to onError")
fastify.addHook('onError', (request, reply, error, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onError', async (request, reply, error) => { // Useful for custom error logging // You should not use this hook to update the error})
This hook is useful if you need to do some custom error logging or add some specific header in case of error.
It is not intended for changing the error, and calling `reply.send` will throw an exception.
This hook will be executed only after the [Custom Error Handler set by `setErrorHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#seterrorhandler)
has been executed, and only if the custom error handler sends an error back to the user _(Note that the default error handler always sends the error back to the user)_.
> 🛈 Note: Unlike the other hooks, passing an error to the `done` function is not supported.
### onSend[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onsend "Direct link to onSend")
If you are using the `onSend` hook, you can change the payload. For example:
fastify.addHook('onSend', (request, reply, payload, done) => { const err = null; const newPayload = payload.replace('some-text', 'some-new-text') done(err, newPayload)})
Or `async/await`:
fastify.addHook('onSend', async (request, reply, payload) => { const newPayload = payload.replace('some-text', 'some-new-text') return newPayload})
You can also clear the payload to send a response with an empty body by replacing the payload with `null`:
fastify.addHook('onSend', (request, reply, payload, done) => { reply.code(304) const newPayload = null done(null, newPayload)})
> You can also send an empty body by replacing the payload with the empty string `''`, but be aware that this will cause the `Content-Length` header to be set to `0`, whereas the `Content-Length` header will not be set if the payload is `null`.
> 🛈 Note: If you change the payload, you may only change it to a `string`, a `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
### onResponse[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onresponse "Direct link to onResponse")
fastify.addHook('onResponse', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onResponse', async (request, reply) => { // Some code await asyncMethod()})
The `onResponse` hook is executed when a response has been sent, so you will not be able to send more data to the client. It can however be useful for sending data to external services, for example, to gather statistics.
> 🛈 Note: Setting `disableRequestLogging` to `true` will disable any error log inside the `onResponse` hook. In this case use `try - catch` to log errors.
### onTimeout[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#ontimeout "Direct link to onTimeout")
fastify.addHook('onTimeout', (request, reply, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onTimeout', async (request, reply) => { // Some code await asyncMethod()})
`onTimeout` is useful if you need to monitor the request timed out in your service (if the `connectionTimeout` property is set on the Fastify instance). The `onTimeout` hook is executed when a request is timed out and the HTTP socket has been hung up. Therefore, you will not be able to send data to the client.
### onRequestAbort[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequestabort "Direct link to onRequestAbort")
fastify.addHook('onRequestAbort', (request, done) => { // Some code done()})
Or `async/await`:
fastify.addHook('onRequestAbort', async (request) => { // Some code await asyncMethod()})
The `onRequestAbort` hook is executed when a client closes the connection before the entire request has been processed. Therefore, you will not be able to send data to the client.
> 🛈 Note: Client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](https://fastify.dev/docs/v5.2.x/Guides/Detecting-When-Clients-Abort/)
### Manage Errors from a hook[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#manage-errors-from-a-hook "Direct link to Manage Errors from a hook")
If you get an error during the execution of your hook, just pass it to `done()` and Fastify will automatically close the request and send the appropriate error code to the user.
fastify.addHook('onRequest', (request, reply, done) => { done(new Error('Some error'))})
If you want to pass a custom error code to the user, just use `reply.code()`:
fastify.addHook('preHandler', (request, reply, done) => { reply.code(400) done(new Error('Some error'))})
_The error will be handled by [`Reply`](https://fastify.dev/docs/v5.2.x/Reference/Reply/#errors)
._
Or if you're using `async/await` you can just throw an error:
fastify.addHook('onRequest', async (request, reply) => { throw new Error('Some error')})
### Respond to a request from a hook[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#respond-to-a-request-from-a-hook "Direct link to Respond to a request from a hook")
If needed, you can respond to a request before you reach the route handler, for example when implementing an authentication hook. Replying from a hook implies that the hook chain is **stopped** and the rest of the hooks and handlers are not executed. If the hook is using the callback approach, i.e. it is not an `async` function or it returns a `Promise`, it is as simple as calling `reply.send()` and avoiding calling the callback. If the hook is `async`, `reply.send()` **must** be called _before_ the function returns or the promise resolves, otherwise, the request will proceed. When `reply.send()` is called outside of the promise chain, it is important to `return reply` otherwise the request will be executed twice.
It is important to **not mix callbacks and `async`/`Promise`**, otherwise the hook chain will be executed twice.
If you are using `onRequest` or `preHandler` use `reply.send`.
fastify.addHook('onRequest', (request, reply, done) => { reply.send('Early response')})// Works with async functions toofastify.addHook('preHandler', async (request, reply) => { setTimeout(() => { reply.send({ hello: 'from prehandler' }) }) return reply // mandatory, so the request is not executed further// Commenting the line above will allow the hooks to continue and fail with FST_ERR_REP_ALREADY_SENT})
If you want to respond with a stream, you should avoid using an `async` function for the hook. If you must use an `async` function, your code will need to follow the pattern in [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275)
.
fastify.addHook('onRequest', (request, reply, done) => { const stream = fs.createReadStream('some-file', 'utf8') reply.send(stream)})
If you are sending a response without `await` on it, make sure to always `return reply`:
fastify.addHook('preHandler', async (request, reply) => { setImmediate(() => { reply.send('hello') }) // This is needed to signal the handler to wait for a response // to be sent outside of the promise chain return reply})fastify.addHook('preHandler', async (request, reply) => { // the @fastify/static plugin will send a file asynchronously, // so we should return reply reply.sendFile('myfile') return reply})
Application Hooks[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#application-hooks "Direct link to Application Hooks")
----------------------------------------------------------------------------------------------------------------------------
You can hook into the application-lifecycle as well.
* [onReady](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onregister)
### onReady[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onready "Direct link to onReady")
Triggered before the server starts listening for requests and when `.ready()` is invoked. It cannot change the routes or add new hooks. Registered hook functions are executed serially. Only after all `onReady` hook functions have completed will the server start listening for requests. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
// callback stylefastify.addHook('onReady', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onReady', async function () { // Some async code await loadCacheFromDatabase()})
### onListen[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onlisten "Direct link to onListen")
Triggered when the server starts listening for requests. The hooks run one after another. If a hook function causes an error, it is logged and ignored, allowing the queue of hooks to continue. Hook functions accept one argument: a callback, `done`, to be invoked after the hook function is complete. Hook functions are invoked with `this` bound to the associated Fastify instance.
This is an alternative to `fastify.server.on('listening', () => {})`.
// callback stylefastify.addHook('onListen', function (done) { // Some code const err = null; done(err)})// or async/await stylefastify.addHook('onListen', async function () { // Some async code})
> 🛈 Note: This hook will not run when the server is started using fastify.inject()`or`fastify.ready()\`.
### onClose[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose "Direct link to onClose")
Triggered when `fastify.close()` is invoked to stop the server, after all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
need a "shutdown" event, for example, to close an open connection to a database.
The hook function takes the Fastify instance as a first argument, and a `done` callback for synchronous hook functions.
// callback stylefastify.addHook('onClose', (instance, done) => { // Some code done()})// or async/await stylefastify.addHook('onClose', async (instance) => { // Some async code await closeDatabaseConnections()})
### preClose[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preclose "Direct link to preClose")
Triggered when `fastify.close()` is invoked to stop the server, before all in-flight HTTP requests have been completed. It is useful when [plugins](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
have set up some state attached to the HTTP server that would prevent the server to close. _It is unlikely you will need to use this hook_, use the [`onClose`](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose)
for the most common case.
// callback stylefastify.addHook('preClose', (done) => { // Some code done()})// or async/await stylefastify.addHook('preClose', async () => { // Some async code await removeSomeServerState()})
### onRoute[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onroute "Direct link to onRoute")
Triggered when a new route is registered. Listeners are passed a [`routeOptions`](https://fastify.dev/docs/v5.2.x/Reference/Routes/#routes-options)
object as the sole parameter. The interface is synchronous, and, as such, the listeners are not passed a callback. This hook is encapsulated.
fastify.addHook('onRoute', (routeOptions) => { //Some code routeOptions.method routeOptions.schema routeOptions.url // the complete URL of the route, it will include the prefix if any routeOptions.path // `url` alias routeOptions.routePath // the URL of the route without the prefix routeOptions.bodyLimit routeOptions.logLevel routeOptions.logSerializers routeOptions.prefix})
If you are authoring a plugin and you need to customize application routes, like modifying the options or adding new route hooks, this is the right place.
fastify.addHook('onRoute', (routeOptions) => { function onPreSerialization(request, reply, payload, done) { // Your code done(null, payload) } // preSerialization can be an array or undefined routeOptions.preSerialization = [...(routeOptions.preSerialization || []), onPreSerialization]})
To add more routes within an onRoute hook, the routes must be tagged correctly. The hook will run into an infinite loop if not tagged. The recommended approach is shown below.
const kRouteAlreadyProcessed = Symbol('route-already-processed')fastify.addHook('onRoute', function (routeOptions) { const { url, method } = routeOptions const isAlreadyProcessed = (routeOptions.custom && routeOptions.custom[kRouteAlreadyProcessed]) || false if (!isAlreadyProcessed) { this.route({ url, method, custom: { [kRouteAlreadyProcessed]: true }, handler: () => {} }) }})
For more details, see this [issue](https://github.com/fastify/fastify/issues/4319)
.
### onRegister[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onregister "Direct link to onRegister")
Triggered when a new plugin is registered and a new encapsulation context is created. The hook will be executed **before** the registered code.
This hook can be useful if you are developing a plugin that needs to know when a plugin context is formed, and you want to operate in that specific context, thus this hook is encapsulated.
> 🛈 Note: This hook will not be called if a plugin is wrapped inside [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
> .
fastify.decorate('data', [])fastify.register(async (instance, opts) => { instance.data.push('hello') console.log(instance.data) // ['hello'] instance.register(async (instance, opts) => { instance.data.push('world') console.log(instance.data) // ['hello', 'world'] }, { prefix: '/hola' })}, { prefix: '/ciao' })fastify.register(async (instance, opts) => { console.log(instance.data) // []}, { prefix: '/hello' })fastify.addHook('onRegister', (instance, opts) => { // Create a new array from the old one // but without keeping the reference // allowing the user to have encapsulated // instances of the `data` property instance.data = instance.data.slice() // the options of the new registered instance console.log(opts.prefix)})
Scope[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#scope "Direct link to Scope")
----------------------------------------------------------------------------------------
Except for [onClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose)
, all hooks are encapsulated. This means that you can decide where your hooks should run by using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.2.x/Guides/Plugins-Guide/)
. If you pass a function, that function is bound to the right Fastify context and from there you have full access to the Fastify API.
fastify.addHook('onRequest', function (request, reply, done) { const self = this // Fastify context done()})
Note that the Fastify context in each hook is the same as the plugin where the route was registered, for example:
fastify.addHook('onRequest', async function (req, reply) { if (req.raw.url === '/nested') { assert.strictEqual(this.foo, 'bar') } else { assert.strictEqual(this.foo, undefined) }})fastify.get('/', async function (req, reply) { assert.strictEqual(this.foo, undefined) return { hello: 'world' }})fastify.register(async function plugin (fastify, opts) { fastify.decorate('foo', 'bar') fastify.get('/nested', async function (req, reply) { assert.strictEqual(this.foo, 'bar') return { hello: 'world' } })})
Warn: if you declare the function with an [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
, the `this` will not be Fastify, but the one of the current scope.
Route level hooks[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#route-level-hooks "Direct link to Route level hooks")
----------------------------------------------------------------------------------------------------------------------------
You can declare one or more custom lifecycle hooks ([onRequest](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
, [onResponse](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onresponse)
, [preParsing](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing)
, [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
, [preHandler](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prehandler)
, [preSerialization](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preserialization)
, [onSend](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onsend)
, [onTimeout](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#ontimeout)
, and [onError](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onerror)
) hook(s) that will be **unique** for the route. If you do so, those hooks are always executed as the last hook in their category.
This can be useful if you need to implement authentication, where the [preParsing](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing)
or [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
hooks are exactly what you need. Multiple route-level hooks can also be specified as an array.
fastify.addHook('onRequest', (request, reply, done) => { // Your code done()})fastify.addHook('onResponse', (request, reply, done) => { // your code done()})fastify.addHook('preParsing', (request, reply, done) => { // Your code done()})fastify.addHook('preValidation', (request, reply, done) => { // Your code done()})fastify.addHook('preHandler', (request, reply, done) => { // Your code done()})fastify.addHook('preSerialization', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onSend', (request, reply, payload, done) => { // Your code done(null, payload)})fastify.addHook('onTimeout', (request, reply, done) => { // Your code done()})fastify.addHook('onError', (request, reply, error, done) => { // Your code done()})fastify.route({ method: 'GET', url: '/', schema: { ... }, onRequest: function (request, reply, done) { // This hook will always be executed after the shared `onRequest` hooks done() }, // // Example with an async hook. All hooks support this syntax // // onRequest: async function (request, reply) { // // This hook will always be executed after the shared `onRequest` hooks // await ... // } onResponse: function (request, reply, done) { // this hook will always be executed after the shared `onResponse` hooks done() }, preParsing: function (request, reply, done) { // This hook will always be executed after the shared `preParsing` hooks done() }, preValidation: function (request, reply, done) { // This hook will always be executed after the shared `preValidation` hooks done() }, preHandler: function (request, reply, done) { // This hook will always be executed after the shared `preHandler` hooks done() }, // // Example with an array. All hooks support this syntax. // // preHandler: [function (request, reply, done) { // // This hook will always be executed after the shared `preHandler` hooks // done() // }], preSerialization: (request, reply, payload, done) => { // This hook will always be executed after the shared `preSerialization` hooks done(null, payload) }, onSend: (request, reply, payload, done) => { // This hook will always be executed after the shared `onSend` hooks done(null, payload) }, onTimeout: (request, reply, done) => { // This hook will always be executed after the shared `onTimeout` hooks done() }, onError: (request, reply, error, done) => { // This hook will always be executed after the shared `onError` hooks done() }, handler: function (request, reply) { reply.send({ hello: 'world' }) }})
> 🛈 Note: Both options also accept an array of functions.
Using Hooks to Inject Custom Properties[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#using-hooks-to-inject-custom-properties "Direct link to Using Hooks to Inject Custom Properties")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
You can use a hook to inject custom properties into incoming requests. This is useful for reusing processed data from hooks in controllers.
A very common use case is, for example, checking user authentication based on their token and then storing their recovered data into the [Request](https://fastify.dev/docs/v5.2.x/Reference/Request/)
instance. This way, your controllers can read it easily with `request.authenticatedUser` or whatever you want to call it. That's how it might look like:
fastify.addHook('preParsing', async (request) => { request.authenticatedUser = { id: 42, name: 'Jane Doe', role: 'admin' }})fastify.get('/me/is-admin', async function (req, reply) { return { isAdmin: req.authenticatedUser?.role === 'admin' || false }})
Note that `.authenticatedUser` could actually be any property name chosen by yourself. Using your own custom property prevents you from mutating existing properties, which would be a dangerous and destructive operation. So be careful and make sure your property is entirely new, also using this approach only for very specific and small cases like this example.
Regarding TypeScript in this example, you'd need to update the `FastifyRequest` core interface to include your new property typing (for more about it, see [TypeScript](https://fastify.dev/docs/v5.2.x/Reference/TypeScript/)
page), like:
interface AuthenticatedUser { /* ... */ }declare module 'fastify' { export interface FastifyRequest { authenticatedUser?: AuthenticatedUser; }}
Although this is a very pragmatic approach, if you're trying to do something more complex that changes these core objects, then consider creating a custom [Plugin](https://fastify.dev/docs/v5.2.x/Reference/Plugins/)
instead.
Diagnostics Channel Hooks[](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#diagnostics-channel-hooks "Direct link to Diagnostics Channel Hooks")
----------------------------------------------------------------------------------------------------------------------------------------------------
One [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
publish event, `'fastify.initialization'`, happens at initialization time. The Fastify instance is passed into the hook as a property of the object passed in. At this point, the instance can be interacted with to add hooks, plugins, routes, or any other sort of modification.
For example, a tracing package might do something like the following (which is, of course, a simplification). This would be in a file loaded in the initialization of the tracking package, in the typical "require instrumentation tools first" fashion.
const tracer = /* retrieved from elsewhere in the package */const dc = require('node:diagnostics_channel')const channel = dc.channel('fastify.initialization')const spans = new WeakMap()channel.subscribe(function ({ fastify }) { fastify.addHook('onRequest', (request, reply, done) => { const span = tracer.startSpan('fastify.request.handler') spans.set(request, span) done() }) fastify.addHook('onResponse', (request, reply, done) => { const span = spans.get(request) span.finish() done() })})
> 🛈 Note: The TracingChannel class API is currently experimental and may undergo breaking changes even in semver-patch releases of Node.js.
Five other events are published on a per-request basis following the [Tracing Channel](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel)
nomenclature. The list of the channel names and the event they receive is:
* `tracing:fastify.request.handler:start`: Always fires
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:end`: Always fires
* `{ request: Request, reply: Reply, route: { url, method }, async: Bool }`
* `tracing:fastify.request.handler:asyncStart`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:asyncEnd`: Fires for promise/async handlers
* `{ request: Request, reply: Reply, route: { url, method } }`
* `tracing:fastify.request.handler:error`: Fires when an error occurs
* `{ request: Request, reply: Reply, route: { url, method }, error: Error }`
The object instance remains the same for all events associated with a given request. All payloads include a `request` and `reply` property which are an instance of Fastify's `Request` and `Reply` instances. They also include a `route` property which is an object with the matched `url` pattern (e.g. `/collection/:id`) and the `method` HTTP method (e.g. `GET`). The `:start` and `:end` events always fire for requests. If a request handler is an `async` function or one that returns a `Promise` then the `:asyncStart` and `:asyncEnd` events also fire. Finally, the `:error` event contains an `error` property associated with the request's failure.
These events can be received like so:
const dc = require('node:diagnostics_channel')const channel = dc.channel('tracing:fastify.request.handler:start')channel.subscribe((msg) => { console.log(msg.request, msg.reply)})
* [Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#hooks)
* [Request/Reply Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#requestreply-hooks)
* [onRequest](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequest)
* [preParsing](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preparsing)
* [preValidation](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prevalidation)
* [preHandler](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#prehandler)
* [preSerialization](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preserialization)
* [onError](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onerror)
* [onSend](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onsend)
* [onResponse](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onresponse)
* [onTimeout](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#ontimeout)
* [onRequestAbort](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onrequestabort)
* [Manage Errors from a hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#manage-errors-from-a-hook)
* [Respond to a request from a hook](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#respond-to-a-request-from-a-hook)
* [Application Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#application-hooks)
* [onReady](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onready)
* [onListen](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onlisten)
* [onClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onclose)
* [preClose](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#preclose)
* [onRoute](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onroute)
* [onRegister](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onregister)
* [Scope](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#scope)
* [Route level hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#route-level-hooks)
* [Using Hooks to Inject Custom Properties](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#using-hooks-to-inject-custom-properties)
* [Diagnostics Channel Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#diagnostics-channel-hooks)
---
# Lifecycle | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Lifecycle/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Lifecycle[](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#lifecycle "Direct link to Lifecycle")
--------------------------------------------------------------------------------------------------------
This schema shows the internal lifecycle of Fastify.
The right branch of each section shows the next phase of the lifecycle. The left branch shows the corresponding error code generated if the parent throws an error. All errors are automatically handled by Fastify.
Incoming Request │ └─▶ Routing │ └─▶ Instance Logger │ 4**/5** ◀─┴─▶ onRequest Hook │ 4**/5** ◀─┴─▶ preParsing Hook │ 4**/5** ◀─┴─▶ Parsing │ 4**/5** ◀─┴─▶ preValidation Hook │ 400 ◀─┴─▶ Validation │ 4**/5** ◀─┴─▶ preHandler Hook │ 4**/5** ◀─┴─▶ User Handler │ └─▶ Reply │ 4**/5** ◀─┴─▶ preSerialization Hook │ └─▶ onSend Hook │ 4**/5** ◀─┴─▶ Outgoing Response │ └─▶ onResponse Hook
Before or during the `User Handler`, `reply.hijack()` can be called to:
* Prevent Fastify from running subsequent hooks and the user handler
* Prevent Fastify from sending the response automatically
If `reply.raw` is used to send a response, `onResponse` hooks will still be executed.
Reply Lifecycle[](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#reply-lifecycle "Direct link to Reply Lifecycle")
--------------------------------------------------------------------------------------------------------------------------
When the user handles the request, the result may be:
* In an async handler: it returns a payload or throws an `Error`
* In a sync handler: it sends a payload or an `Error` instance
If the reply was hijacked, all subsequent steps are skipped. Otherwise, when submitted, the data flow is as follows:
★ schema validation Error │ └─▶ schemaErrorFormatter │ reply sent ◀── JSON ─┴─ Error instance │ │ ★ throw an Error ★ send or return │ │ │ │ │ │ ▼ │ reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler ◀─────┘ │ reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook │ └─▶ reply sent
`reply sent` means the JSON payload will be serialized by one of the following:
* The [reply serializer](https://fastify.dev/docs/v5.2.x/Reference/Server/#setreplyserializer)
if set
* The [serializer compiler](https://fastify.dev/docs/v5.2.x/Reference/Server/#setserializercompiler)
if a JSON schema is set for the HTTP status code
* The default `JSON.stringify` function
* [Lifecycle](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#lifecycle)
* [Reply Lifecycle](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#reply-lifecycle)
---
# Logging | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Logging/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Logging/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Logging[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#logging "Direct link to Logging")
------------------------------------------------------------------------------------------------
### Enable Logging[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#enable-logging "Direct link to Enable Logging")
Logging is disabled by default. Enable it by passing `{ logger: true }` or `{ logger: { level: 'info' } }` when creating a Fastify instance. Note that if the logger is disabled, it cannot be enabled at runtime. [abstract-logging](https://www.npmjs.com/package/abstract-logging)
is used for this purpose.
As Fastify is focused on performance, it uses [pino](https://github.com/pinojs/pino)
as its logger, with the default log level set to `'info'` when enabled.
#### Basic logging setup[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#basic-logging-setup "Direct link to Basic logging setup")
Enabling the production JSON logger:
const fastify = require('fastify')({ logger: true})
#### Environment-Specific Configuration[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#environment-specific-configuration "Direct link to Environment-Specific Configuration")
Enabling the logger with appropriate configuration for local development, production, and test environments requires more configuration:
const envToLogger = { development: { transport: { target: 'pino-pretty', options: { translateTime: 'HH:MM:ss Z', ignore: 'pid,hostname', }, }, }, production: true, test: false,}const fastify = require('fastify')({ logger: envToLogger[environment] ?? true // defaults to true if no entry matches in the map})
⚠️ `pino-pretty` needs to be installed as a dev dependency. It is not included by default for performance reasons.
### Usage[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#usage "Direct link to Usage")
The logger can be used in route handlers as follows:
fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
Trigger new logs outside route handlers using the Pino instance from the Fastify instance:
fastify.log.info('Something important happened!');
#### Passing Logger Options[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#passing-logger-options "Direct link to Passing Logger Options")
To pass options to the logger, provide them to Fastify. See the [Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options)
for available options. To specify a file destination, use:
const fastify = require('fastify')({ logger: { level: 'info', file: '/path/to/file' // Will use pino.destination() }})fastify.get('/', options, function (request, reply) { request.log.info('Some info about the current request') reply.send({ hello: 'world' })})
To pass a custom stream to the Pino instance, add a `stream` field to the logger object:
const split = require('split2')const stream = split(JSON.parse)const fastify = require('fastify')({ logger: { level: 'info', stream: stream }})
### Advanced Logger Configuration[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#advanced-logger-configuration "Direct link to Advanced Logger Configuration")
#### Request ID Tracking[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#request-id-tracking "Direct link to Request ID Tracking")
By default, Fastify adds an ID to every request for easier tracking. If the `requestIdHeader` option is set and the corresponding header is present, its value is used; otherwise, a new incremental ID is generated. See Fastify Factory [`requestIdHeader`](https://fastify.dev/docs/v5.2.x/Reference/Server/#factory-request-id-header)
and Fastify Factory [`genReqId`](https://fastify.dev/docs/v5.2.x/Reference/Server/#genreqid)
for customization options.
#### Serializers[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#serializers "Direct link to Serializers")
The default logger uses standard serializers for objects with `req`, `res`, and `err` properties. The `req` object is the Fastify [`Request`](https://fastify.dev/docs/v5.2.x/Reference/Request/)
object, and the `res` object is the Fastify [`Reply`](https://fastify.dev/docs/v5.2.x/Reference/Reply/)
object. This behavior can be customized with custom serializers.
const fastify = require('fastify')({ logger: { serializers: { req (request) { return { url: request.url } } } }})
For example, the response payload and headers could be logged using the approach below (not recommended):
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode } }, req (request) { return { method: request.method, url: request.url, path: request.routeOptions.url, parameters: request.params, // Including headers in the log could violate privacy laws, // e.g., GDPR. Use the "redact" option to remove sensitive // fields. It could also leak authentication data in the logs. headers: request.headers }; } } }});
> 🛈 Note: In some cases, the [`Reply`](https://fastify.dev/docs/v5.2.x/Reference/Reply/)
> object passed to the `res` serializer cannot be fully constructed. When writing a custom `res` serializer, check for the existence of any properties on `reply` aside from `statusCode`, which is always present. For example, verify the existence of `getHeaders` before calling it:
const fastify = require('fastify')({ logger: { transport: { target: 'pino-pretty' }, serializers: { res (reply) { // The default return { statusCode: reply.statusCode, headers: typeof reply.getHeaders === 'function' ? reply.getHeaders() : {} } }, } }});
> 🛈 Note: The body cannot be serialized inside a `req` method because the request is serialized when the child logger is created. At that time, the body is not yet parsed.
See the following approach to log `req.body`:
app.addHook('preHandler', function (req, reply, done) { if (req.body) { req.log.info({ body: req.body }, 'parsed body') } done()})
> 🛈 Note: Ensure serializers never throw errors, as this can cause the Node process to exit. See the [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers)
> for more information.
_Any logger other than Pino will ignore this option._
### Using Custom Loggers[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#using-custom-loggers "Direct link to Using Custom Loggers")
A custom logger instance can be supplied by passing it as `loggerInstance`. The logger must conform to the Pino interface, with methods: `info`, `error`, `debug`, `fatal`, `warn`, `trace`, `silent`, `child`, and a string property `level`.
Example:
const log = require('pino')({ level: 'info' })const fastify = require('fastify')({ loggerInstance: log })log.info('does not have request information')fastify.get('/', function (request, reply) { request.log.info('includes request information, but is the same logger instance as `log`') reply.send({ hello: 'world' })})
_The logger instance for the current request is available in every part of the [lifecycle](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/)
._
### Log Redaction[](https://fastify.dev/docs/v5.2.x/Reference/Logging/#log-redaction "Direct link to Log Redaction")
[Pino](https://getpino.io/)
supports low-overhead log redaction for obscuring values of specific properties in recorded logs. For example, log all HTTP headers except the `Authorization` header for security:
const fastify = Fastify({ logger: { stream: stream, redact: ['req.headers.authorization'], level: 'info', serializers: { req (request) { return { method: request.method, url: request.url, headers: request.headers, host: request.host, remoteAddress: request.ip, remotePort: request.socket.remotePort } } } }})
See [https://getpino.io/#/docs/redaction](https://getpino.io/#/docs/redaction)
for more details.
* [Logging](https://fastify.dev/docs/v5.2.x/Reference/Logging/#logging)
* [Enable Logging](https://fastify.dev/docs/v5.2.x/Reference/Logging/#enable-logging)
* [Usage](https://fastify.dev/docs/v5.2.x/Reference/Logging/#usage)
* [Advanced Logger Configuration](https://fastify.dev/docs/v5.2.x/Reference/Logging/#advanced-logger-configuration)
* [Using Custom Loggers](https://fastify.dev/docs/v5.2.x/Reference/Logging/#using-custom-loggers)
* [Log Redaction](https://fastify.dev/docs/v5.2.x/Reference/Logging/#log-redaction)
---
# Middleware | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Middleware/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Middleware[](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#middleware "Direct link to Middleware")
------------------------------------------------------------------------------------------------------------
Starting with Fastify v3.0.0, middleware is not supported out of the box and requires an external plugin such as [`@fastify/express`](https://github.com/fastify/fastify-express)
or [`@fastify/middie`](https://github.com/fastify/middie)
.
An example of registering the [`@fastify/express`](https://github.com/fastify/fastify-express)
plugin to `use` Express middleware:
await fastify.register(require('@fastify/express'))fastify.use(require('cors')())fastify.use(require('dns-prefetch-control')())fastify.use(require('frameguard')())fastify.use(require('hsts')())fastify.use(require('ienoopen')())fastify.use(require('x-xss-protection')())
[`@fastify/middie`](https://github.com/fastify/middie)
can also be used, which provides support for simple Express-style middleware with improved performance:
await fastify.register(require('@fastify/middie'))fastify.use(require('cors')())
Middleware can be encapsulated, allowing control over where it runs using `register` as explained in the [plugins guide](https://fastify.dev/docs/v5.2.x/Guides/Plugins-Guide/)
.
Fastify middleware does not expose the `send` method or other methods specific to the Fastify [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply)
instance. This is because Fastify wraps the incoming `req` and `res` Node instances using the [Request](https://fastify.dev/docs/v5.2.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply)
objects internally, but this is done after the middleware phase. To create middleware, use the Node `req` and `res` instances. Alternatively, use the `preHandler` hook that already has the Fastify [Request](https://fastify.dev/docs/v5.2.x/Reference/Request/#request)
and [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply)
instances. For more information, see [Hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#hooks)
.
#### Restrict middleware execution to certain paths[](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#restrict-middleware-execution-to-certain-paths "Direct link to Restrict middleware execution to certain paths")
To run middleware under certain paths, pass the path as the first parameter to `use`.
> 🛈 Note: This does not support routes with parameters (e.g. `/user/:id/comments`) and wildcards are not supported in multiple paths.
const path = require('node:path')const serveStatic = require('serve-static')// Single pathfastify.use('/css', serveStatic(path.join(__dirname, '/assets')))// Wildcard pathfastify.use('/css/(.*)', serveStatic(path.join(__dirname, '/assets')))// Multiple pathsfastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
### Alternatives[](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#alternatives "Direct link to Alternatives")
Fastify offers alternatives to commonly used middleware, such as [`@fastify/helmet`](https://github.com/fastify/fastify-helmet)
for [`helmet`](https://github.com/helmetjs/helmet)
, [`@fastify/cors`](https://github.com/fastify/fastify-cors)
for [`cors`](https://github.com/expressjs/cors)
, and [`@fastify/static`](https://github.com/fastify/fastify-static)
for [`serve-static`](https://github.com/expressjs/serve-static)
.
* [Middleware](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#middleware)
* [Alternatives](https://fastify.dev/docs/v5.2.x/Reference/Middleware/#alternatives)
---
# Plugins | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Plugins/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Plugins[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#plugins "Direct link to Plugins")
------------------------------------------------------------------------------------------------
Fastify can be extended with plugins, which can be a set of routes, a server [decorator](https://fastify.dev/docs/v5.2.x/Reference/Decorators/)
, or other functionality. Use the `register` API to add one or more plugins.
By default, `register` creates a _new scope_, meaning changes to the Fastify instance (via `decorate`) will not affect the current context ancestors, only its descendants. This feature enables plugin _encapsulation_ and _inheritance_, creating a _directed acyclic graph_ (DAG) and avoiding cross-dependency issues.
The [Getting Started](https://fastify.dev/docs/v5.2.x/Guides/Getting-Started/#your-first-plugin)
guide includes an example of using this API:
fastify.register(plugin, [options])
### Plugin Options[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#plugin-options "Direct link to Plugin Options")
The optional `options` parameter for `fastify.register` supports a predefined set of options that Fastify itself will use, except when the plugin has been wrapped with [fastify-plugin](https://github.com/fastify/fastify-plugin)
. This options object will also be passed to the plugin upon invocation, regardless of whether or not the plugin has been wrapped. The currently supported list of Fastify specific options is:
* [`logLevel`](https://fastify.dev/docs/v5.2.x/Reference/Routes/#custom-log-level)
* [`logSerializers`](https://fastify.dev/docs/v5.2.x/Reference/Routes/#custom-log-serializer)
* [`prefix`](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#route-prefixing-option)
These options will be ignored when used with fastify-plugin.
To avoid collisions, a plugin should consider namespacing its options. For example, a plugin `foo` might be registered like so:
fastify.register(require('fastify-foo'), { prefix: '/foo', foo: { fooOption1: 'value', fooOption2: 'value' }})
If collisions are not a concern, the plugin may accept the options object as-is:
fastify.register(require('fastify-foo'), { prefix: '/foo', fooOption1: 'value', fooOption2: 'value'})
The `options` parameter can also be a `Function` evaluated at plugin registration, providing access to the Fastify instance via the first argument:
const fp = require('fastify-plugin')fastify.register(fp((fastify, opts, done) => { fastify.decorate('foo_bar', { hello: 'world' }) done()}))// The opts argument of fastify-foo will be { hello: 'world' }fastify.register(require('fastify-foo'), parent => parent.foo_bar)
The Fastify instance passed to the function is the latest state of the **external Fastify instance** the plugin was declared on, allowing access to variables injected via [`decorate`](https://fastify.dev/docs/v5.2.x/Reference/Decorators/)
by preceding plugins according to the **order of registration**. This is useful if a plugin depends on changes made to the Fastify instance by a preceding plugin, such as utilizing an existing database connection.
Keep in mind that the Fastify instance passed to the function is the same as the one passed into the plugin, a copy of the external Fastify instance rather than a reference. Any usage of the instance will behave the same as it would if called within the plugin's function. For example, if `decorate` is called, the decorated variables will be available within the plugin's function unless it was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
.
#### Route Prefixing option[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#route-prefixing-option "Direct link to Route Prefixing option")
If an option with the key `prefix` and a `string` value is passed, Fastify will use it to prefix all the routes inside the register. For more info, check [here](https://fastify.dev/docs/v5.2.x/Reference/Routes/#route-prefixing)
.
Be aware that if routes are wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
, this option will not work (see the [workaround](https://fastify.dev/docs/v5.2.x/Reference/Routes/#fastify-plugin)
).
#### Error handling[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#error-handling "Direct link to Error handling")
Error handling is done by [avvio](https://github.com/mcollina/avvio#error-handling)
.
As a general rule, handle errors in the next `after` or `ready` block, otherwise they will be caught inside the `listen` callback.
fastify.register(require('my-plugin'))// `after` will be executed once// the previous declared `register` has finishedfastify.after(err => console.log(err))// `ready` will be executed once all the registers declared// have finished their executionfastify.ready(err => console.log(err))// `listen` is a special ready,// so it behaves in the same wayfastify.listen({ port: 3000 }, (err, address) => { if (err) console.log(err)})
### async/await[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#asyncawait "Direct link to async/await")
_async/await_ is supported by `after`, `ready`, and `listen`, as well as `fastify` being a Thenable.
await fastify.register(require('my-plugin'))await fastify.after()await fastify.ready()await fastify.listen({ port: 3000 })
Using `await` when registering a plugin loads the plugin and its dependencies, "finalizing" the encapsulation process. Any mutations to the plugin after it and its dependencies have been loaded will not be reflected in the parent instance.
#### ESM support[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#esm-support "Direct link to ESM support")
ESM is supported from [Node.js `v13.3.0`](https://nodejs.org/api/esm.html)
and above.
// main.mjsimport Fastify from 'fastify'const fastify = Fastify()fastify.register(import('./plugin.mjs'))fastify.listen({ port: 3000 }, console.log)// plugin.mjsasync function plugin (fastify, opts) { fastify.get('/', async (req, reply) => { return { hello: 'world' } })}export default plugin
### Create a plugin[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#create-a-plugin "Direct link to Create a plugin")
Creating a plugin is easy. Create a function that takes three parameters: the `fastify` instance, an `options` object, and the `done` callback.
Example:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) done()}
`register` can also be used inside another `register`:
module.exports = function (fastify, opts, done) { fastify.decorate('utility', function () {}) fastify.get('/', handler) fastify.register(require('./other-plugin')) done()}
Remember, `register` always creates a new Fastify scope. If this is not needed, read the following section.
### Handle the scope[](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#handle-the-scope "Direct link to Handle the scope")
If `register` is used only to extend server functionality with [`decorate`](https://fastify.dev/docs/v5.2.x/Reference/Decorators/)
, tell Fastify not to create a new scope. Otherwise, changes will not be accessible in the upper scope.
There are two ways to avoid creating a new context:
* Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
module
* Use the `'skip-override'` hidden property
Using the `fastify-plugin` module is recommended, as it solves this problem and allows passing a version range of Fastify that the plugin will support:
const fp = require('fastify-plugin')module.exports = fp(function (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}, '0.x')
Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
documentation to learn more about how to use this module.
If not using `fastify-plugin`, the `'skip-override'` hidden property can be used, but it is not recommended. Future Fastify API changes will be your responsibility to update, whilst `fastify-plugin` ensures backward compatibility.
function yourPlugin (fastify, opts, done) { fastify.decorate('utility', function () {}) done()}yourPlugin[Symbol.for('skip-override')] = truemodule.exports = yourPlugin
* [Plugins](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#plugins)
* [Plugin Options](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#plugin-options)
* [async/await](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#asyncawait)
* [Create a plugin](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#create-a-plugin)
* [Handle the scope](https://fastify.dev/docs/v5.2.x/Reference/Plugins/#handle-the-scope)
---
# Technical Principles | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Principles/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Principles/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Every decision in the Fastify framework and its official plugins is guided by the following technical principles:
1. “Zero” overhead in production
2. “Good” developer experience
3. Works great for small & big projects alike
4. Easy to migrate to microservices (or even serverless) and back
5. Security & data validation
6. If something could be a plugin, it likely should be
7. Easily testable
8. Do not monkeypatch core
9. Semantic versioning & Long Term Support
10. Specification adherence
"Zero" Overhead in Production[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#zero-overhead-in-production "Direct link to "Zero" Overhead in Production")
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to implement features with minimal overhead. This is achieved by using fast algorithms, data structures, and JavaScript-specific features.
Since JavaScript does not offer zero-overhead data structures, this principle can conflict with providing a great developer experience and additional features, as these usually incur some overhead.
"Good" Developer Experience[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#good-developer-experience "Direct link to "Good" Developer Experience")
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Fastify aims to provide the best developer experience at its performance point. It offers a great out-of-the-box experience that is flexible enough to adapt to various situations.
For example, binary addons are forbidden because most JavaScript developers do not have access to a compiler.
Works great for small and big projects alike[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#works-great-for-small-and-big-projects-alike "Direct link to Works great for small and big projects alike")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Most applications start small and become more complex over time. Fastify aims to grow with this complexity, providing advanced features to structure codebases.
Easy to migrate to microservices (or even serverless) and back[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back "Direct link to Easy to migrate to microservices (or even serverless) and back")
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Route deployment should not matter. The framework should "just work".
Security and Data Validation[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#security-and-data-validation "Direct link to Security and Data Validation")
------------------------------------------------------------------------------------------------------------------------------------------------------------------
A web framework is the first point of contact with untrusted data and must act as the first line of defense for the system.
If something could be a plugin, it likely should[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should "Direct link to If something could be a plugin, it likely should")
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Recognizing the infinite use cases for an HTTP framework, catering to all in a single module would make the codebase unmaintainable. Therefore, hooks and options are provided to customize the framework as needed.
Easily testable[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#easily-testable "Direct link to Easily testable")
---------------------------------------------------------------------------------------------------------------------------
Testing Fastify applications should be a first-class concern.
Do not monkeypatch core[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#do-not-monkeypatch-core "Direct link to Do not monkeypatch core")
---------------------------------------------------------------------------------------------------------------------------------------------------
Monkeypatching Node.js APIs or installing globals that alter the runtime makes building modular applications harder and limits Fastify's use cases. Other frameworks do this; Fastify does not.
Semantic Versioning and Long Term Support[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#semantic-versioning-and-long-term-support "Direct link to Semantic Versioning and Long Term Support")
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
A clear [Long Term Support strategy is provided](https://fastify.dev/docs/v5.2.x/Reference/LTS/)
to inform developers when to upgrade.
Specification adherence[](https://fastify.dev/docs/v5.2.x/Reference/Principles/#specification-adherence "Direct link to Specification adherence")
---------------------------------------------------------------------------------------------------------------------------------------------------
In doubt, we chose the strict behavior as defined by the relevant Specifications.
* ["Zero" Overhead in Production](https://fastify.dev/docs/v5.2.x/Reference/Principles/#zero-overhead-in-production)
* ["Good" Developer Experience](https://fastify.dev/docs/v5.2.x/Reference/Principles/#good-developer-experience)
* [Works great for small and big projects alike](https://fastify.dev/docs/v5.2.x/Reference/Principles/#works-great-for-small-and-big-projects-alike)
* [Easy to migrate to microservices (or even serverless) and back](https://fastify.dev/docs/v5.2.x/Reference/Principles/#easy-to-migrate-to-microservices-or-even-serverless-and-back)
* [Security and Data Validation](https://fastify.dev/docs/v5.2.x/Reference/Principles/#security-and-data-validation)
* [If something could be a plugin, it likely should](https://fastify.dev/docs/v5.2.x/Reference/Principles/#if-something-could-be-a-plugin-it-likely-should)
* [Easily testable](https://fastify.dev/docs/v5.2.x/Reference/Principles/#easily-testable)
* [Do not monkeypatch core](https://fastify.dev/docs/v5.2.x/Reference/Principles/#do-not-monkeypatch-core)
* [Semantic Versioning and Long Term Support](https://fastify.dev/docs/v5.2.x/Reference/Principles/#semantic-versioning-and-long-term-support)
* [Specification adherence](https://fastify.dev/docs/v5.2.x/Reference/Principles/#specification-adherence)
---
# Reply | Fastify
[Skip to main content](https://fastify.dev/docs/v5.2.x/Reference/Reply/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/Reply/)
** (latest (v5.4.x)).
Version: v5.2.x
On this page
Reply[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply "Direct link to Reply")
----------------------------------------------------------------------------------------
* [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.2.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.2.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.2.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.2.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headerkey-value)
* [.headers(object)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#redirectdest--code)
* [.callNotFound()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getserializationfunctionschema--httpstatus)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#compileserializationschemaschema-httpstatus)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus)
* [.serializer(func)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.2.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.2.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#senddata)
* [Objects](https://fastify.dev/docs/v5.2.x/Reference/Reply/#objects)
* [Strings](https://fastify.dev/docs/v5.2.x/Reference/Reply/#strings)
* [Streams](https://fastify.dev/docs/v5.2.x/Reference/Reply/#streams)
* [Buffers](https://fastify.dev/docs/v5.2.x/Reference/Reply/#buffers)
* [TypedArrays](https://fastify.dev/docs/v5.2.x/Reference/Reply/#typedarrays)
* [ReadableStream](https://fastify.dev/docs/v5.2.x/Reference/Reply/#readablestream)
* [Response](https://fastify.dev/docs/v5.2.x/Reference/Reply/#response)
* [Errors](https://fastify.dev/docs/v5.2.x/Reference/Reply/#errors)
* [Type of the final payload](https://fastify.dev/docs/v5.2.x/Reference/Reply/#type-of-the-final-payload)
* [Async-Await and Promises](https://fastify.dev/docs/v5.2.x/Reference/Reply/#async-await-and-promises)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#thenfulfilled-rejected)
### Introduction[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#introduction "Direct link to Introduction")
The second parameter of the handler function is `Reply`. Reply is a core Fastify object that exposes the following functions and properties:
* `.code(statusCode)` - Sets the status code.
* `.status(statusCode)` - An alias for `.code(statusCode)`.
* `.statusCode` - Read and set the HTTP status code.
* `.elapsedTime` - Returns the amount of time passed since the request was received by Fastify.
* `.server` - A reference to the fastify instance object.
* `.header(name, value)` - Sets a response header.
* `.headers(object)` - Sets all the keys of the object as response headers.
* `.getHeader(name)` - Retrieve value of already set header.
* `.getHeaders()` - Gets a shallow copy of all current response headers.
* `.removeHeader(key)` - Remove the value of a previously set header.
* `.hasHeader(name)` - Determine if a header has been set.
* `.writeEarlyHints(hints, callback)` - Sends early hints to the user while the response is being prepared.
* `.trailer(key, function)` - Sets a response trailer.
* `.hasTrailer(key)` - Determine if a trailer has been set.
* `.removeTrailer(key)` - Remove the value of a previously set trailer.
* `.type(value)` - Sets the header `Content-Type`.
* `.redirect(dest, [code,])` - Redirect to the specified URL, the status code is optional (defaults to `302`).
* `.callNotFound()` - Invokes the custom not found handler.
* `.serialize(payload)` - Serializes the specified payload using the default JSON serializer or using the custom serializer (if one is set) and returns the serialized payload.
* `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the serialization function for the specified schema or http status, if any of either are set.
* `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles the specified schema and returns a serialization function using the default (or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded to the `SerializerCompiler` if provided, default to `undefined`.
* `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes the specified data using the specified schema and returns the serialized payload. If the optional `httpStatus`, and `contentType` are provided, the function will use the serializer function given for that specific content type and HTTP Status Code. Default to `undefined`.
* `.serializer(function)` - Sets a custom serializer for the payload.
* `.send(payload)` - Sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object.
* `.sent` - A boolean value that you can use if you need to know if `send` has already been called.
* `.hijack()` - interrupt the normal request lifecycle.
* `.raw` - The [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core.
* `.log` - The logger instance of the incoming request.
* `.request` - The incoming request.
fastify.get('/', options, function (request, reply) { // Your code reply .code(200) .header('Content-Type', 'application/json; charset=utf-8') .send({ hello: 'world' })})
### .code(statusCode)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#codestatuscode "Direct link to .code(statusCode)")
If not set via `reply.code`, the resulting `statusCode` will be `200`.
### .elapsedTime[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#elapsedtime "Direct link to .elapsedTime")
Invokes the custom response time getter to calculate the amount of time passed since the request was received by Fastify.
const milliseconds = reply.elapsedTime
### .statusCode[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#statuscode "Direct link to .statusCode")
This property reads and sets the HTTP status code. It is an alias for `reply.code()` when used as a setter.
if (reply.statusCode >= 299) { reply.statusCode = 500}
### .server[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#server "Direct link to .server")
The Fastify server instance, scoped to the current [encapsulation context](https://fastify.dev/docs/v5.2.x/Reference/Encapsulation/)
.
fastify.decorate('util', function util () { return 'foo'})fastify.get('/', async function (req, rep) { return rep.server.util() // foo})
### .header(key, value)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headerkey-value "Direct link to .header(key, value)")
Sets a response header. If the value is omitted or undefined, it is coerced to `''`.
> 🛈 Note: The header's value must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid characters will result in a 500 `TypeError` response.
For more information, see [`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value)
.
* ### set-cookie[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#set-cookie "Direct link to set-cookie")
* When sending different values as a cookie with `set-cookie` as the key, every value will be sent as a cookie instead of replacing the previous value.
reply.header('set-cookie', 'foo');reply.header('set-cookie', 'bar');
* The browser will only consider the latest reference of a key for the `set-cookie` header. This is done to avoid parsing the `set-cookie` header when added to a reply and speeds up the serialization of the reply.
* To reset the `set-cookie` header, you need to make an explicit call to `reply.removeHeader('set-cookie')`, read more about `.removeHeader(key)` [here](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removeheaderkey)
.
### .headers(object)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headersobject "Direct link to .headers(object)")
Sets all the keys of the object as response headers. [`.header`](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headerkey-value)
will be called under the hood.
reply.headers({ 'x-foo': 'foo', 'x-bar': 'bar'})
### .getHeader(key)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaderkey "Direct link to .getHeader(key)")
Retrieves the value of a previously set header.
reply.header('x-foo', 'foo') // setHeader: key, valuereply.getHeader('x-foo') // 'foo'
### .getHeaders()[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaders "Direct link to .getHeaders()")
Gets a shallow copy of all current response headers, including those set via the raw `http.ServerResponse`. Note that headers set via Fastify take precedence over those set via `http.ServerResponse`.
reply.header('x-foo', 'foo')reply.header('x-bar', 'bar')reply.raw.setHeader('x-foo', 'foo2')reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }
### .removeHeader(key)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removeheaderkey "Direct link to .removeHeader(key)")
Remove the value of a previously set header.
reply.header('x-foo', 'foo')reply.removeHeader('x-foo')reply.getHeader('x-foo') // undefined
### .hasHeader(key)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hasheaderkey "Direct link to .hasHeader(key)")
Returns a boolean indicating if the specified header has been set.
### .writeEarlyHints(hints, callback)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#writeearlyhintshints-callback "Direct link to .writeEarlyHints(hints, callback)")
Sends early hints to the client. Early hints allow the client to start processing resources before the final response is sent. This can improve performance by allowing the client to preload or preconnect to resources while the server is still generating the response.
The hints parameter is an object containing the early hint key-value pairs.
Example:
reply.writeEarlyHints({ Link: '; rel=preload; as=style'});
The optional callback parameter is a function that will be called once the hint is sent or if an error occurs.
### .trailer(key, function)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#trailerkey-function "Direct link to .trailer(key, function)")
Sets a response trailer. Trailer is usually used when you need a header that requires heavy resources to be sent after the `data`, for example, `Server-Timing` and `Etag`. It can ensure the client receives the response data as soon as possible.
> 🛈 Note: The header `Transfer-Encoding: chunked` will be added once you use the trailer. It is a hard requirement for using trailer in Node.js.
> 🛈 Note: Any error passed to `done` callback will be ignored. If you interested in the error, you can turn on `debug` level logging.\*
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})const { createHash } = require('node:crypto')// trailer function also receive two argument// @param {object} reply fastify reply// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent// @param {function} done callback to set trailer valuereply.trailer('content-md5', function(reply, payload, done) { const hash = createHash('md5') hash.update(payload) done(null, hash.disgest('hex'))})// when you prefer async-awaitreply.trailer('content-md5', async function(reply, payload) { const hash = createHash('md5') hash.update(payload) return hash.disgest('hex')})
### .hasTrailer(key)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hastrailerkey "Direct link to .hasTrailer(key)")
Returns a boolean indicating if the specified trailer has been set.
### .removeTrailer(key)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removetrailerkey "Direct link to .removeTrailer(key)")
Remove the value of a previously set trailer.
reply.trailer('server-timing', function() { return 'db;dur=53, app;dur=47.2'})reply.removeTrailer('server-timing')reply.getTrailer('server-timing') // undefined
### .redirect(dest, \[code ,\])[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#redirectdest-code- "Direct link to .redirect(dest, [code ,])")
Redirects a request to the specified URL, the status code is optional, default to `302` (if status code is not already set by calling `code`).
> 🛈 Note: The input URL must be properly encoded using [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
> or similar modules such as [`encodeurl`](https://www.npmjs.com/package/encodeurl)
> . Invalid URLs will result in a 500 `TypeError` response.
Example (no `reply.code()` call) sets status code to `302` and redirects to `/home`
reply.redirect('/home')
Example (no `reply.code()` call) sets status code to `303` and redirects to `/home`
reply.redirect('/home', 303)
Example (`reply.code()` call) sets status code to `303` and redirects to `/home`
reply.code(303).redirect('/home')
Example (`reply.code()` call) sets status code to `302` and redirects to `/home`
reply.code(303).redirect('/home', 302)
### .callNotFound()[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#callnotfound "Direct link to .callNotFound()")
Invokes the custom not found handler. Note that it will only call `preHandler` hook specified in [`setNotFoundHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#set-not-found-handler)
.
reply.callNotFound()
### .type(contentType)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#typecontenttype "Direct link to .type(contentType)")
Sets the content type for the response. This is a shortcut for `reply.header('Content-Type', 'the/type')`.
reply.type('text/html')
If the `Content-Type` has a JSON subtype, and the charset parameter is not set, `utf-8` will be used as the charset by default. For other content types, the charset must be set explicitly.
### .getSerializationFunction(schema | httpStatus, \[contentType\])[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype "Direct link to .getSerializationFunction(schema | httpStatus, [contentType])")
By calling this function using a provided `schema` or `httpStatus`, and the optional `contentType`, it will return a `serialzation` function that can be used to serialize diverse inputs. It returns `undefined` if no serialization function was found using either of the provided inputs.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .getSerializationFunction({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .getSerializationFunction(200, 'application/json')serialize({ foo: 'bar' }) // '{"foo":"bar"}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .compileSerializationSchema(schema, \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype "Direct link to .compileSerializationSchema(schema, [httpStatus], [contentType])")
This function will compile a serialization schema and return a function that can be used to serialize data. The function returned (a.k.a. _serialization function_) returned is compiled by using the provided `SerializerCompiler`. Also this is cached by using a `WeakMap` for reducing compilation calls.
The optional parameters `httpStatus` and `contentType`, if provided, are forwarded directly to the `SerializerCompiler`, so it can be used to compile the serialization function if a custom `SerializerCompiler` is used.
This heavily depends of the `schema#responses` attached to the route, or the serialization functions compiled by using `compileSerializationSchema`.
const serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } })serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ type: 'object', properties: { foo: { type: 'string' } } }, 200)serialize({ foo: 'bar' }) // '{"foo":"bar"}'// orconst serialize = reply .compileSerializationSchema({ '3xx': { content: { 'application/json': { schema: { name: { type: 'string' }, phone: { type: 'number' } } } } } }, '3xx', 'application/json')serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'
Note that you should be careful when using this function, as it will cache the compiled serialization functions based on the schema provided. If the schemas provided is mutated or changed, the serialization functions will not detect that the schema has been altered and for instance it will reuse the previously compiled serialization function based on the reference of the schema previously provided.
If there's a need to change the properties of a schema, always opt to create a totally new object, otherwise the implementation won't benefit from the cache mechanism.
:Using the following schema as example:
const schema1 = { type: 'object', properties: { foo: { type: 'string' } }}
_Not_
const serialize = reply.compileSerializationSchema(schema1)// Later on...schema1.properties.foo.type. = 'integer'const newSerialize = reply.compileSerializationSchema(schema1)console.log(newSerialize === serialize) // true
_Instead_
const serialize = reply.compileSerializationSchema(schema1)// Later on...const newSchema = Object.assign({}, schema1)newSchema.properties.foo.type = 'integer'const newSerialize = reply.compileSerializationSchema(newSchema)console.log(newSerialize === serialize) // false
### .serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype "Direct link to .serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])")
This function will serialize the input data based on the provided schema or HTTP status code. If both are provided the `httpStatus` will take precedence.
If there is not a serialization function for a given `schema` a new serialization function will be compiled, forwarding the `httpStatus` and `contentType` if provided.
reply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, { type: 'object', properties: { foo: { type: 'string' } } }, 200) // '{"foo":"bar"}'// orreply .serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'// orreply .serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'
See [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#compileserializationschema)
for more information on how to compile serialization schemas.
### .serializer(func)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializerfunc "Direct link to .serializer(func)")
By default, `.send()` will JSON-serialize any value that is not one of `Buffer`, `stream`, `string`, `undefined`, or `Error`. If you need to replace the default serializer with a custom serializer for a particular request, you can do so with the `.serializer()` utility. Be aware that if you are using a custom serializer, you must set a custom `'Content-Type'` header.
reply .header('Content-Type', 'application/x-protobuf') .serializer(protoBuf.serialize)
Note that you don't need to use this utility inside a `handler` because Buffers, streams, and strings (unless a serializer is set) are considered to already be serialized.
reply .header('Content-Type', 'application/x-protobuf') .send(protoBuf.serialize(data))
See [`.send()`](https://fastify.dev/docs/v5.2.x/Reference/Reply/#send)
for more information on sending different types of values.
### .raw[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#raw "Direct link to .raw")
This is the [`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
from Node core. Whilst you are using the Fastify `Reply` object, the use of `Reply.raw` functions is at your own risk as you are skipping all the Fastify logic of handling the HTTP response. e.g.:
app.get('/cookie-2', (req, reply) => { reply.setCookie('session', 'value', { secure: false }) // this will not be used // in this case we are using only the nodejs http server response object reply.raw.writeHead(200, { 'Content-Type': 'text/plain' }) reply.raw.write('ok') reply.raw.end()})
Another example of the misuse of `Reply.raw` is explained in [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaders)
.
### .sent[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#sent "Direct link to .sent")
As the name suggests, `.sent` is a property to indicate if a response has been sent via `reply.send()`. It will also be `true` in case `reply.hijack()` was used.
In case a route handler is defined as an async function or it returns a promise, it is possible to call `reply.hijack()` to indicate that the automatic invocation of `reply.send()` once the handler promise resolve should be skipped. By calling `reply.hijack()`, an application claims full responsibility for the low-level request and response. Moreover, hooks will not be invoked.
_Modifying the `.sent` property directly is deprecated. Please use the aforementioned `.hijack()` method to achieve the same effect._
### .hijack()[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hijack "Direct link to .hijack()")
Sometimes you might need to halt the execution of the normal request lifecycle and handle sending the response manually.
To achieve this, Fastify provides the `reply.hijack()` method that can be called during the request lifecycle (At any point before `reply.send()` is called), and allows you to prevent Fastify from sending the response, and from running the remaining hooks (and user handler if the reply was hijacked before).
app.get('/', (req, reply) => { reply.hijack() reply.raw.end('hello world') return Promise.resolve('this will be skipped')})
If `reply.raw` is used to send a response back to the user, the `onResponse` hooks will still be executed.
### .send(data)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#senddata "Direct link to .send(data)")
As the name suggests, `.send()` is the function that sends the payload to the end user.
#### Objects[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#objects "Direct link to Objects")
As noted above, if you are sending JSON objects, `send` will serialize the object with [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
if you set an output schema, otherwise, `JSON.stringify()` will be used.
fastify.get('/json', options, function (request, reply) { reply.send({ hello: 'world' })})
#### Strings[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#strings "Direct link to Strings")
If you pass a string to `send` without a `Content-Type`, it will be sent as `text/plain; charset=utf-8`. If you set the `Content-Type` header and pass a string to `send`, it will be serialized with the custom serializer if one is set, otherwise, it will be sent unmodified (unless the `Content-Type` header is set to `application/json; charset=utf-8`, in which case it will be JSON-serialized like an object — see the section above).
fastify.get('/json', options, function (request, reply) { reply.send('plain string')})
#### Streams[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#streams "Direct link to Streams")
If you are sending a stream and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, streams are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') reply.send(stream)})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { const stream = fs.createReadStream('some-file', 'utf8') reply.header('Content-Type', 'application/octet-stream') return reply.send(stream)})
#### Buffers[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#buffers "Direct link to Buffers")
If you are sending a buffer and you have not set a `'Content-Type'` header, _send_ will set it to `'application/octet-stream'`.
As noted above, Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) })})
When using async-await you will need to return or await the reply object:
const fs = require('node:fs')fastify.get('/streams', async function (request, reply) { fs.readFile('some-file', (err, fileBuffer) => { reply.send(err || fileBuffer) }) return reply})
#### TypedArrays[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#typedarrays "Direct link to TypedArrays")
`send` manages TypedArray like a Buffer, and sets the `'Content-Type'` header to `'application/octet-stream'` if not already set.
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')fastify.get('/streams', function (request, reply) { const typedArray = new Uint16Array(10) reply.send(typedArray)})
#### ReadableStream[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#readablestream "Direct link to ReadableStream")
`ReadableStream` will be treated as a node stream mentioned above, the content is considered to be pre-serialized, so they will be sent unmodified without response validation.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') reply.header('Content-Type', 'application/octet-stream') reply.send(ReadableStream.from(stream))})
#### Response[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#response "Direct link to Response")
`Response` allows to manage the reply payload, status code and headers in one place. The payload provided inside `Response` is considered to be pre-serialized, so they will be sent unmodified without response validation.
Please be aware when using `Response`, the status code and headers will not directly reflect to `reply.statusCode` and `reply.getHeaders()`. Such behavior is based on `Response` only allow `readonly` status code and headers. The data is not allow to be bi-direction editing, and may confuse when checking the `payload` in `onSend` hooks.
const fs = require('node:fs')const { ReadableStream } = require('node:stream/web')fastify.get('/streams', function (request, reply) { const stream = fs.createReadStream('some-file') const readableStream = ReadableStream.from(stream) const response = new Response(readableStream, { status: 200, headers: { 'content-type': 'application/octet-stream' } }) reply.send(response)})
#### Errors[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#errors "Direct link to Errors")
If you pass to _send_ an object that is an instance of _Error_, Fastify will automatically create an error structured as the following:
{ error: String // the HTTP error message code: String // the Fastify error code message: String // the user error message statusCode: Number // the HTTP status code}
You can add custom properties to the Error object, such as `headers`, that will be used to enhance the HTTP response.
> 🛈 Note: If you are passing an error to `send` and the statusCode is less than 400, Fastify will automatically set it at 500.
Tip: you can simplify errors by using the [`http-errors`](https://npm.im/http-errors)
module or [`@fastify/sensible`](https://github.com/fastify/fastify-sensible)
plugin to generate errors:
fastify.get('/', function (request, reply) { reply.send(httpErrors.Gone())})
To customize the JSON error output you can do it by:
* setting a response JSON schema for the status code you need
* add the additional properties to the `Error` instance
Notice that if the returned status code is not in the response schema list, the default behavior will be applied.
fastify.get('/', { schema: { response: { 501: { type: 'object', properties: { statusCode: { type: 'number' }, code: { type: 'string' }, error: { type: 'string' }, message: { type: 'string' }, time: { type: 'string' } } } } }}, function (request, reply) { const error = new Error('This endpoint has not been implemented') error.time = 'it will be implemented in two weeks' reply.code(501).send(error)})
If you want to customize error handling, check out [`setErrorHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#seterrorhandler)
API.
> 🛈 Note: you are responsible for logging when customizing the error handler.
API:
fastify.setErrorHandler(function (error, request, reply) { request.log.warn(error) const statusCode = error.statusCode >= 400 ? error.statusCode : 500 reply .code(statusCode) .type('text/plain') .send(statusCode >= 500 ? 'Internal server error' : error.message)})
Beware that calling `reply.send(error)` in your custom error handler will send the error to the default error handler. Check out the [Reply Lifecycle](https://fastify.dev/docs/v5.2.x/Reference/Lifecycle/#reply-lifecycle)
for more information.
The not found errors generated by the router will use the [`setNotFoundHandler`](https://fastify.dev/docs/v5.2.x/Reference/Server/#setnotfoundhandler)
API:
fastify.setNotFoundHandler(function (request, reply) { reply .code(404) .type('text/plain') .send('a custom not found')})
#### Type of the final payload[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#type-of-the-final-payload "Direct link to Type of the final payload")
The type of the sent payload (after serialization and going through any [`onSend` hooks](https://fastify.dev/docs/v5.2.x/Reference/Hooks/#onsend)
) must be one of the following types, otherwise, an error will be thrown:
* `string`
* `Buffer`
* `stream`
* `undefined`
* `null`
#### Async-Await and Promises[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#async-await-and-promises "Direct link to Async-Await and Promises")
Fastify natively handles promises and supports async-await.
_Note that in the following examples we are not using reply.send._
const { promisify } = require('node:util')const delay = promisify(setTimeout)fastify.get('/promises', options, function (request, reply) { return delay(200).then(() => { return { hello: 'world' }})})fastify.get('/async-await', options, async function (request, reply) { await delay(200) return { hello: 'world' }})
Rejected promises default to a `500` HTTP status code. Reject the promise, or `throw` in an `async function`, with an object that has `statusCode` (or `status`) and `message` properties to modify the reply.
fastify.get('/teapot', async function (request, reply) { const err = new Error() err.statusCode = 418 err.message = 'short and stout' throw err})fastify.get('/botnet', async function (request, reply) { throw { statusCode: 418, message: 'short and stout' } // will return to the client the same json})
If you want to know more please review [Routes#async-await](https://fastify.dev/docs/v5.2.x/Reference/Routes/#async-await)
.
### .then(fulfilled, rejected)[](https://fastify.dev/docs/v5.2.x/Reference/Reply/#thenfulfilled-rejected "Direct link to .then(fulfilled, rejected)")
As the name suggests, a `Reply` object can be awaited upon, i.e. `await reply` will wait until the reply is sent. The `await` syntax calls the `reply.then()`.
`reply.then(fulfilled, rejected)` accepts two parameters:
* `fulfilled` will be called when a response has been fully sent,
* `rejected` will be called if the underlying stream had an error, e.g. the socket has been destroyed.
For more details, see:
* [https://github.com/fastify/fastify/issues/1864](https://github.com/fastify/fastify/issues/1864)
for the discussion about this feature
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Promise/then](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
for the signature
* [Reply](https://fastify.dev/docs/v5.2.x/Reference/Reply/#reply)
* [Introduction](https://fastify.dev/docs/v5.2.x/Reference/Reply/#introduction)
* [.code(statusCode)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#codestatuscode)
* [.elapsedTime](https://fastify.dev/docs/v5.2.x/Reference/Reply/#elapsedtime)
* [.statusCode](https://fastify.dev/docs/v5.2.x/Reference/Reply/#statuscode)
* [.server](https://fastify.dev/docs/v5.2.x/Reference/Reply/#server)
* [.header(key, value)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headerkey-value)
* [set-cookie](https://fastify.dev/docs/v5.2.x/Reference/Reply/#set-cookie)
* [.headers(object)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#headersobject)
* [.getHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaderkey)
* [.getHeaders()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getheaders)
* [.removeHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removeheaderkey)
* [.hasHeader(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hasheaderkey)
* [.writeEarlyHints(hints, callback)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#writeearlyhintshints-callback)
* [.trailer(key, function)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#trailerkey-function)
* [.hasTrailer(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hastrailerkey)
* [.removeTrailer(key)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#removetrailerkey)
* [.redirect(dest, \[code ,\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#redirectdest-code-)
* [.callNotFound()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#callnotfound)
* [.type(contentType)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#typecontenttype)
* [.getSerializationFunction(schema | httpStatus, \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#getserializationfunctionschema--httpstatus-contenttype)
* [.compileSerializationSchema(schema, \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#compileserializationschemaschema-httpstatus-contenttype)
* [.serializeInput(data, \[schema | httpStatus\], \[httpStatus\], \[contentType\])](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializeinputdata-schema--httpstatus-httpstatus-contenttype)
* [.serializer(func)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#serializerfunc)
* [.raw](https://fastify.dev/docs/v5.2.x/Reference/Reply/#raw)
* [.sent](https://fastify.dev/docs/v5.2.x/Reference/Reply/#sent)
* [.hijack()](https://fastify.dev/docs/v5.2.x/Reference/Reply/#hijack)
* [.send(data)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#senddata)
* [.then(fulfilled, rejected)](https://fastify.dev/docs/v5.2.x/Reference/Reply/#thenfulfilled-rejected)
---
# ContentTypeParser | Fastify
[Skip to main content](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#__docusaurus_skipToContent_fallback)
For up-to-date documentation, see the **[latest version](https://fastify.dev/docs/latest/Reference/ContentTypeParser/)
** (latest (v5.4.x)).
Version: v5.1.x
On this page
`Content-Type` Parser[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#content-type-parser "Direct link to content-type-parser")
------------------------------------------------------------------------------------------------------------------------------------------------
Natively, Fastify only supports `'application/json'` and `'text/plain'` content types. If the content type is not one of these, an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error will be thrown. Other common content types are supported through the use of [plugins](https://fastify.dev/ecosystem/)
.
The default charset is `utf-8`. If you need to support different content types, you can use the `addContentTypeParser` API. _The default JSON and/or plain text parser can be changed or removed._
_Note: If you decide to specify your own content type with the `Content-Type` header, UTF-8 will not be the default. Be sure to include UTF-8 like this `text/html; charset=utf-8`._
As with the other APIs, `addContentTypeParser` is encapsulated in the scope in which it is declared. This means that if you declare it in the root scope it will be available everywhere, while if you declare it inside a plugin it will be available only in that scope and its children.
Fastify automatically adds the parsed request payload to the [Fastify request](https://fastify.dev/docs/v5.1.x/Reference/Request/)
object which you can access with `request.body`.
Note that for `GET` and `HEAD` requests the payload is never parsed. For `OPTIONS` and `DELETE` requests the payload is only parsed if the content type is given in the content-type header. If it is not given, the [catch-all](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#catch-all)
parser is not executed as with `POST`, `PUT` and `PATCH`, but the payload is simply not parsed.
> ⚠ Security Notice[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#--security-notice "Direct link to ⚠ Security Notice")
>
> -----------------------------------------------------------------------------------------------------------------------------------------
>
> When using with RegExp to detect `Content-Type`, you should beware of how to properly detect the `Content-Type`. For example, if you need `application/*`, you should use `/^application\/([\w-]+);?/` to match the [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#usage "Direct link to Usage")
fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) })})// Handle multiple content types with the same functionfastify.addContentTypeParser(['text/xml', 'application/xml'], function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Async is also supported in Node versions >= 8.0.0fastify.addContentTypeParser('application/jsoff', async function (request, payload) { const res = await jsoffParserAsync(payload) return res})// Handle all content types that matches RegExpfastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) { imageParser(payload, function (err, body) { done(err, body) })})// Can use default JSON/Text parser for different content Typesfastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
Fastify first tries to match a content-type parser with a `string` value before trying to find a matching `RegExp`. If you provide overlapping content types, Fastify tries to find a matching content type by starting with the last one passed and ending with the first one. So if you want to specify a general content type more precisely, first specify the general content type and then the more specific one, like in the example below.
// Here only the second content type parser is called because its value also matches the first onefastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )// Here the desired behavior is achieved because fastify first tries to match the// `application/vnd.custom+xml` content type parserfastify.addContentTypeParser('application/vnd.custom', (request, body, done) => {} )fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
### Using addContentTypeParser with fastify.register[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister "Direct link to Using addContentTypeParser with fastify.register")
When using `addContentTypeParser` in combination with `fastify.register`, `await` should not be used when registering routes. Using `await` causes the route registration to be asynchronous and can lead to routes being registered before the addContentTypeParser has been set.
#### Correct Usage[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#correct-usage "Direct link to Correct Usage")
const fastify = require('fastify')();fastify.register((fastify, opts) => { fastify.addContentTypeParser('application/json', function (request, payload, done) { jsonParser(payload, function (err, body) { done(err, body) }) }) fastify.get('/hello', async (req, res) => {});});
Besides the `addContentTypeParser` API there are further APIs that can be used. These are `hasContentTypeParser`, `removeContentTypeParser` and `removeAllContentTypeParsers`.
#### hasContentTypeParser[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#hascontenttypeparser "Direct link to hasContentTypeParser")
You can use the `hasContentTypeParser` API to find if a specific content type parser already exists.
if (!fastify.hasContentTypeParser('application/jsoff')){ fastify.addContentTypeParser('application/jsoff', function (request, payload, done) { jsoffParser(payload, function (err, body) { done(err, body) }) })}
#### removeContentTypeParser[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#removecontenttypeparser "Direct link to removeContentTypeParser")
With `removeContentTypeParser` a single or an array of content types can be removed. The method supports `string` and `RegExp` content types.
fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})// Removes the both built-in content type parsers so that only the content type parser for text/html is availablefastify.removeContentTypeParser(['application/json', 'text/plain'])
#### removeAllContentTypeParsers[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#removeallcontenttypeparsers "Direct link to removeAllContentTypeParsers")
In the example from just above, it is noticeable that we need to specify each content type that we want to remove. To solve this problem Fastify provides the `removeAllContentTypeParsers` API. This can be used to remove all currently existing content type parsers. In the example below we achieve the same as in the example above except that we do not need to specify each content type to delete. Just like `removeContentTypeParser`, this API supports encapsulation. The API is especially useful if you want to register a [catch-all content type parser](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#catch-all)
that should be executed for every content type and the built-in parsers should be ignored as well.
fastify.removeAllContentTypeParsers()fastify.addContentTypeParser('text/xml', function (request, payload, done) { xmlParser(payload, function (err, body) { done(err, body) })})
**Notice**: The old syntaxes `function(req, done)` and `async function(req)` for the parser are still supported but they are deprecated.
#### Body Parser[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#body-parser "Direct link to Body Parser")
You can parse the body of a request in two ways. The first one is shown above: you add a custom content type parser and handle the request stream. In the second one, you should pass a `parseAs` option to the `addContentTypeParser` API, where you declare how you want to get the body. It could be of type `'string'` or `'buffer'`. If you use the `parseAs` option, Fastify will internally handle the stream and perform some checks, such as the [maximum size](https://fastify.dev/docs/v5.1.x/Reference/Server/#factory-body-limit)
of the body and the content length. If the limit is exceeded the custom parser will not be invoked.
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) { try { const json = JSON.parse(body) done(null, json) } catch (err) { err.statusCode = 400 done(err, undefined) }})
See [`example/parser.js`](https://github.com/fastify/fastify/blob/main/examples/parser.js)
for an example.
##### Custom Parser Options[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#custom-parser-options "Direct link to Custom Parser Options")
* `parseAs` (string): Either `'string'` or `'buffer'` to designate how the incoming data should be collected. Default: `'buffer'`.
* `bodyLimit` (number): The maximum payload size, in bytes, that the custom parser will accept. Defaults to the global body limit passed to the [`Fastify factory function`](https://fastify.dev/docs/v5.1.x/Reference/Server/#bodylimit)
.
#### Catch-All[](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#catch-all "Direct link to Catch-All")
There are some cases where you need to catch all requests regardless of their content type. With Fastify, you can just use the `'*'` content type.
fastify.addContentTypeParser('*', function (request, payload, done) { let data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
Using this, all requests that do not have a corresponding content type parser will be handled by the specified function.
This is also useful for piping the request stream. You can define a content parser like:
fastify.addContentTypeParser('*', function (request, payload, done) { done()})
and then access the core HTTP request directly for piping it where you want:
app.post('/hello', (request, reply) => { reply.send(request.raw)})
Here is a complete example that logs incoming [json line](https://jsonlines.org/)
objects:
const split2 = require('split2')const pump = require('pump')fastify.addContentTypeParser('*', (request, payload, done) => { done(null, pump(payload, split2(JSON.parse)))})fastify.route({ method: 'POST', url: '/api/log/jsons', handler: (req, res) => { req.body.on('data', d => console.log(d)) // log every incoming object }})
For piping file uploads you may want to check out [this plugin](https://github.com/fastify/fastify-multipart)
.
If you want the content type parser to be executed on all content types and not only on those that don't have a specific one, you should call the `removeAllContentTypeParsers` method first.
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parserfastify.removeAllContentTypeParsers()fastify.addContentTypeParser('*', function (request, payload, done) { const data = '' payload.on('data', chunk => { data += chunk }) payload.on('end', () => { done(null, data) })})
* [`Content-Type` Parser](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#content-type-parser)
* [⚠ Security Notice](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#--security-notice)
* [Usage](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#usage)
* [Using addContentTypeParser with fastify.register](https://fastify.dev/docs/v5.1.x/Reference/ContentTypeParser/#using-addcontenttypeparser-with-fastifyregister)
---