# V4 Migration Guide

This guide is intended to help with migration from Fastify v3 to v4.

Before migrating to v4, please ensure that you have fixed all deprecation
warnings from v3. All v3 deprecations have been removed and they will no longer
work after upgrading.

## Breaking Changes

### Error handling composition ([#3261](https://github.com/fastify/fastify/pull/3261))

When an error is thrown in an async error handler function, the upper-level
error handler is executed if set. If there is no upper-level error handler,
the default will be executed as it was previously:

```js
import Fastify from 'fastify'

const fastify = Fastify()

fastify.register(async fastify => {
  fastify.setErrorHandler(async err => {
    console.log(err.message) // 'kaboom'
    throw new Error('caught')
  })
  
  fastify.get('/encapsulated', async () => {
    throw new Error('kaboom')
  })
})

fastify.setErrorHandler(async err => {
  console.log(err.message) // 'caught' 
  throw new Error('wrapped')
})

const res = await fastify.inject('/encapsulated')
console.log(res.json().message) // 'wrapped'
```

### Removed `app.use()` ([#3506](https://github.com/fastify/fastify/pull/3506))

With v4 of Fastify, `app.use()` has been removed and the use of middleware is
no longer supported.

If you need to use middleware, use
[`@fastify/middie`](https://github.com/fastify/middie) or
[`@fastify/express`](https://github.com/fastify/fastify-express), which will
continue to be maintained.
However, it is strongly recommended that you migrate to Fastify's [hooks](../Reference/Hooks.md).

### `reply.res` moved to `reply.raw`

If you previously used the `reply.res` attribute to access the underlying Request
object you will now need to use `reply.raw`.

### Need to `return reply` to signal a "fork" of the promise chain

In some situations, like when a response is sent asynchronously or when you are
not explicitly returning a response, you will now need to return the `reply`
argument from your router handler.

### `exposeHeadRoutes` true by default

Starting with v4, every `GET` route will create a sibling `HEAD` route.
You can revert this behavior by setting `exposeHeadRoutes: false` in the server options.

### Synchronous route definitions ([#2954](https://github.com/fastify/fastify/pull/2954))

To improve error reporting in route definitions, route registration is now synchronous.
As a result, if you specify an `onRoute` hook in a plugin you should now either:
* wrap your routes in a plugin (recommended)

  For example, refactor this:
  ```js
  fastify.register((instance, opts, done) => {
    instance.addHook('onRoute', (routeOptions) => {
      const { path, method } = routeOptions;
      console.log({ path, method });
      done();
    });
  });

  fastify.get('/', (request, reply) => { reply.send('hello') });
  ```

  Into this:
  ```js
  fastify.register((instance, opts, done) => {
    instance.addHook('onRoute', (routeOptions) => {
      const { path, method } = routeOptions;
      console.log({ path, method });
      done();
    });
  });

  fastify.register((instance, opts, done) => {
    instance.get('/', (request, reply) => { reply.send('hello') });
    done();
  });
  ```

* use `await register(...)`

  For example, refactor this:
  ```js
  fastify.register((instance, opts, done) => {
    instance.addHook('onRoute', (routeOptions) => {
      const { path, method } = routeOptions;
      console.log({ path, method });
    });
    done();
  });
  ```

  Into this:
  ```js
  await fastify.register((instance, opts) => {
    instance.addHook('onRoute', (routeOptions) => {
      const { path, method } = routeOptions;
      console.log({ path, method });
    });
    done();
  });
  ```

## Non-Breaking Changes

### Deprecation of variadic `.listen()` signature

The [variadic signature](https://en.wikipedia.org/wiki/Variadic_function) of the
`fastify.listen()` method is now deprecated.

Prior to this release, the following invocations of this method were valid:

  - `fastify.listen(8000)`
  - `fastify.listen(8000, ‘127.0.0.1’)`
  - `fastify.listen(8000, ‘127.0.0.1’, 511)`
  - `fastify.listen(8000, (err) => { if (err) throw err })`
  - `fastify.listen({ port: 8000 }, (err) => { if (err) throw err })`

With Fastify v4, only the following invocations are valid:

  - `fastify.listen()`
  - `fastify.listen({ port: 8000 })`
  - `fastify.listen({ port: 8000 }, (err) => { if (err) throw err })`

### Change of schema for multiple types

Ajv has been upgraded to v8 in Fastify v4, meaning "type" keywords with multiple
types other than "null"
[are now prohibited](https://ajv.js.org/strict-mode.html#strict-types).

You may encounter a console warning such as:
```sh
strict mode: use allowUnionTypes to allow union type keyword at "#/properties/image" (strictTypes)
```

As such, schemas like below will need to be changed from:
```
type: 'object',
properties: {
  api_key: { type: 'string' },
  image: { type: ['object', 'array'] }
  }
}
```

Into:
```
type: 'object',
properties: {
  api_key: { type: 'string' },
  image: {
    anyOf: [
      { type: 'array' },
      { type: 'object' }
    ]
  }
}
```

### Add `reply.trailers` methods ([#3794](https://github.com/fastify/fastify/pull/3794))

Fastify now supports the [HTTP Trailer] response headers.


[HTTP Trailer]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer
