|  |  |  |  | # V3 Migration Guide
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | This guide is intended to help with migration from Fastify v2 to v3. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | Before beginning please ensure that any deprecation warnings from v2 are fixed. | 
					
						
							|  |  |  |  | All v2 deprecations have been removed and they will no longer work after | 
					
						
							|  |  |  |  | upgrading. ([#1750](https://github.com/fastify/fastify/pull/1750)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ## Breaking changes
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed middleware support ([#2014](https://github.com/fastify/fastify/pull/2014))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | From Fastify v3, middleware support does not come out-of-the-box with the | 
					
						
							|  |  |  |  | framework itself. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | If you use Express middleware in your application, please install and register | 
					
						
							|  |  |  |  | the [`@fastify/express`](https://github.com/fastify/fastify-express) or | 
					
						
							|  |  |  |  | [`middie`](https://github.com/fastify/middie) plugin before doing so. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | // Using the Express `cors` middleware in Fastify v2. | 
					
						
							|  |  |  |  | fastify.use(require('cors')()); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | // Using the Express `cors` middleware in Fastify v3. | 
					
						
							|  |  |  |  | await fastify.register(require('@fastify/express')); | 
					
						
							|  |  |  |  | fastify.use(require('cors')()); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed logging serialization ([#2017](https://github.com/fastify/fastify/pull/2017))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The logging [Serializers](../Reference/Logging.md) have been updated to now | 
					
						
							|  |  |  |  | Fastify [`Request`](../Reference/Request.md) and | 
					
						
							|  |  |  |  | [`Reply`](../Reference/Reply.md) objects instead of native ones. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | Any custom serializers must be updated if they rely upon `request` or `reply` | 
					
						
							|  |  |  |  | properties that are present on the native objects but not the Fastify objects. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const fastify = require('fastify')({ | 
					
						
							|  |  |  |  |   logger: { | 
					
						
							|  |  |  |  |     serializers: { | 
					
						
							|  |  |  |  |       res(res) { | 
					
						
							|  |  |  |  |         return { | 
					
						
							|  |  |  |  |           statusCode: res.statusCode, | 
					
						
							|  |  |  |  |           customProp: res.customProp | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const fastify = require('fastify')({ | 
					
						
							|  |  |  |  |   logger: { | 
					
						
							|  |  |  |  |     serializers: { | 
					
						
							|  |  |  |  |       res(reply) { | 
					
						
							|  |  |  |  |         return { | 
					
						
							|  |  |  |  |           statusCode: reply.statusCode, // No change required | 
					
						
							|  |  |  |  |           customProp: reply.raw.customProp // Log custom property from res object | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed schema substitution ([#2023](https://github.com/fastify/fastify/pull/2023))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The non-standard `replace-way` shared schema support has been removed. This | 
					
						
							|  |  |  |  | feature has been replaced with JSON Schema specification compliant `$ref` based | 
					
						
							|  |  |  |  | substitution. To help understand this change read [Validation and Serialization | 
					
						
							|  |  |  |  | in Fastify | 
					
						
							|  |  |  |  | v3](https://dev.to/eomm/validation-and-serialization-in-fastify-v3-2e8l). | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const schema = { | 
					
						
							|  |  |  |  |   body: 'schemaId#' | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | fastify.route({ method, url, schema, handler }); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const schema = { | 
					
						
							|  |  |  |  |   body: { | 
					
						
							|  |  |  |  |     $ref: 'schemaId#' | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | fastify.route({ method, url, schema, handler }); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed schema validation options ([#2023](https://github.com/fastify/fastify/pull/2023))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The `setSchemaCompiler` and `setSchemaResolver` options have been replaced with | 
					
						
							|  |  |  |  | the `setValidatorCompiler` to enable future tooling improvements. To help | 
					
						
							|  |  |  |  | understand this change read [Validation and Serialization in Fastify | 
					
						
							|  |  |  |  | v3](https://dev.to/eomm/validation-and-serialization-in-fastify-v3-2e8l). | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const fastify = Fastify(); | 
					
						
							|  |  |  |  | const ajv = new AJV(); | 
					
						
							|  |  |  |  | ajv.addSchema(schemaA); | 
					
						
							|  |  |  |  | ajv.addSchema(schemaB); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | fastify.setSchemaCompiler(schema => ajv.compile(schema)); | 
					
						
							|  |  |  |  | fastify.setSchemaResolver(ref => ajv.getSchema(ref).schema); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | const fastify = Fastify(); | 
					
						
							|  |  |  |  | const ajv = new AJV(); | 
					
						
							|  |  |  |  | ajv.addSchema(schemaA); | 
					
						
							|  |  |  |  | ajv.addSchema(schemaB); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => | 
					
						
							|  |  |  |  |   ajv.compile(schema) | 
					
						
							|  |  |  |  | ); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed preParsing hook behavior ([#2286](https://github.com/fastify/fastify/pull/2286))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | From Fastify v3, the behavior of the `preParsing` hook will change slightly in | 
					
						
							|  |  |  |  | order to support request payload manipulation. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The hook now takes an additional argument, `payload`, and therefore the new hook | 
					
						
							|  |  |  |  | signature is `fn(request, reply, payload, done)` or `async fn(request, reply, | 
					
						
							|  |  |  |  | payload)`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The hook can optionally return a new stream via `done(null, stream)` or | 
					
						
							|  |  |  |  | returning the stream in case of async functions. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | If the hook returns a new stream, it will be used instead of the original one in | 
					
						
							|  |  |  |  | subsequent hooks. A sample use case for this is handling compressed requests. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The new stream should add the `receivedEncodedLength` property to the stream | 
					
						
							|  |  |  |  | that should reflect the actual data size received from the client. For instance, | 
					
						
							|  |  |  |  | in a compressed request it should be the size of the compressed payload. This | 
					
						
							|  |  |  |  | property can (and should) be dynamically updated during `data` events. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The old syntax of Fastify v2 without payload is supported but it is deprecated. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed hooks behavior ([#2004](https://github.com/fastify/fastify/pull/2004))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | From Fastify v3, the behavior of `onRoute` and `onRegister` hooks will change | 
					
						
							|  |  |  |  | slightly in order to support hook encapsulation. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - `onRoute` - The hook will be called asynchronously. The hook is now inherited | 
					
						
							|  |  |  |  |   when registering a new plugin within the same encapsulation scope. Thus, this | 
					
						
							|  |  |  |  |   hook should be registered _before_ registering any plugins. | 
					
						
							|  |  |  |  | - `onRegister` - Same as the onRoute hook. The only difference is that now the | 
					
						
							|  |  |  |  |   very first call will no longer be the framework itself, but the first | 
					
						
							|  |  |  |  |   registered plugin. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed Content Type Parser syntax ([#2286](https://github.com/fastify/fastify/pull/2286))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | In Fastify v3 the content type parsers now have a single signature for parsers. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The new signatures are `fn(request, payload, done)` or `async fn(request, | 
					
						
							|  |  |  |  | payload)`. Note that `request` is now a Fastify request, not an | 
					
						
							|  |  |  |  | `IncomingMessage`. The payload is by default a stream. If the `parseAs` option | 
					
						
							|  |  |  |  | is used in `addContentTypeParser`, then `payload` reflects the option value | 
					
						
							|  |  |  |  | (string or buffer). | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | The old signatures `fn(req, [done])` or `fn(req, payload, [done])` (where `req` | 
					
						
							|  |  |  |  | is `IncomingMessage`) are still supported but are deprecated. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Changed TypeScript support
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 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! | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```ts | 
					
						
							|  |  |  |  | interface PingQuerystring { | 
					
						
							|  |  |  |  |   foo?: number; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | interface PingParams { | 
					
						
							|  |  |  |  |   bar?: string; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | interface PingHeaders { | 
					
						
							|  |  |  |  |   a?: string; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | interface PingBody { | 
					
						
							|  |  |  |  |   baz?: string; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | server.get<PingQuerystring, PingParams, PingHeaders, PingBody>( | 
					
						
							|  |  |  |  |   '/ping/:bar', | 
					
						
							|  |  |  |  |   opts, | 
					
						
							|  |  |  |  |   (request, reply) => { | 
					
						
							|  |  |  |  |     console.log(request.query); // This is of type `PingQuerystring` | 
					
						
							|  |  |  |  |     console.log(request.params); // This is of type `PingParams` | 
					
						
							|  |  |  |  |     console.log(request.headers); // This is of type `PingHeaders` | 
					
						
							|  |  |  |  |     console.log(request.body); // This is of type `PingBody` | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | ); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```ts | 
					
						
							|  |  |  |  | server.get<{ | 
					
						
							|  |  |  |  |   Querystring: PingQuerystring; | 
					
						
							|  |  |  |  |   Params: PingParams; | 
					
						
							|  |  |  |  |   Headers: PingHeaders; | 
					
						
							|  |  |  |  |   Body: PingBody; | 
					
						
							|  |  |  |  | }>('/ping/:bar', opts, async (request, reply) => { | 
					
						
							|  |  |  |  |   console.log(request.query); // This is of type `PingQuerystring` | 
					
						
							|  |  |  |  |   console.log(request.params); // This is of type `PingParams` | 
					
						
							|  |  |  |  |   console.log(request.headers); // This is of type `PingHeaders` | 
					
						
							|  |  |  |  |   console.log(request.body); // This is of type `PingBody` | 
					
						
							|  |  |  |  | }); | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ### Manage uncaught exception ([#2073](https://github.com/fastify/fastify/pull/2073))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | In sync route handlers, if an error was thrown the server crashed by design | 
					
						
							|  |  |  |  | without calling the configured `.setErrorHandler()`. This has changed and now | 
					
						
							|  |  |  |  | all unexpected errors in sync and async routes are managed. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v2:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | fastify.setErrorHandler((error, request, reply) => { | 
					
						
							|  |  |  |  |   // this is NOT called | 
					
						
							|  |  |  |  |   reply.send(error) | 
					
						
							|  |  |  |  | }) | 
					
						
							|  |  |  |  | fastify.get('/', (request, reply) => { | 
					
						
							|  |  |  |  |   const maybeAnArray = request.body.something ? [] : 'I am a string' | 
					
						
							|  |  |  |  |   maybeAnArray.substr() // Thrown: [].substr is not a function and crash the server | 
					
						
							|  |  |  |  | }) | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | **v3:** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ```js | 
					
						
							|  |  |  |  | fastify.setErrorHandler((error, request, reply) => { | 
					
						
							|  |  |  |  |   // this IS called | 
					
						
							|  |  |  |  |   reply.send(error) | 
					
						
							|  |  |  |  | }) | 
					
						
							|  |  |  |  | fastify.get('/', (request, reply) => { | 
					
						
							|  |  |  |  |   const maybeAnArray = request.body.something ? [] : 'I am a string' | 
					
						
							|  |  |  |  |   maybeAnArray.substr() // Thrown: [].substr is not a function, but it is handled | 
					
						
							|  |  |  |  | }) | 
					
						
							|  |  |  |  | ``` | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | ## Further additions and improvements
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - Hooks now have consistent context regardless of how they are registered | 
					
						
							|  |  |  |  |   ([#2005](https://github.com/fastify/fastify/pull/2005)) | 
					
						
							|  |  |  |  | - Deprecated `request.req` and `reply.res` for | 
					
						
							|  |  |  |  |   [`request.raw`](../Reference/Request.md) and | 
					
						
							|  |  |  |  |   [`reply.raw`](../Reference/Reply.md) | 
					
						
							|  |  |  |  |   ([#2008](https://github.com/fastify/fastify/pull/2008)) | 
					
						
							|  |  |  |  | - Removed `modifyCoreObjects` option | 
					
						
							|  |  |  |  |   ([#2015](https://github.com/fastify/fastify/pull/2015)) | 
					
						
							|  |  |  |  | - Added [`connectionTimeout`](../Reference/Server.md#factory-connection-timeout) | 
					
						
							|  |  |  |  |   option ([#2086](https://github.com/fastify/fastify/pull/2086)) | 
					
						
							|  |  |  |  | - Added [`keepAliveTimeout`](../Reference/Server.md#factory-keep-alive-timeout) | 
					
						
							|  |  |  |  |   option ([#2086](https://github.com/fastify/fastify/pull/2086)) | 
					
						
							|  |  |  |  | - Added async-await support for [plugins](../Reference/Plugins.md#async-await) | 
					
						
							|  |  |  |  |   ([#2093](https://github.com/fastify/fastify/pull/2093)) | 
					
						
							|  |  |  |  | - Added the feature to throw object as error | 
					
						
							|  |  |  |  |   ([#2134](https://github.com/fastify/fastify/pull/2134)) |