@fastify/express

中文文档
4.0.9发布于 2026/10/27MITTypeScriptCommonJS构建来源已验证近 30 天下载 39.7万

Express compatibility layer for Fastify

原始使用文档
文档目录13 节
  1. Install
  2. Compatibility
  3. Usage
  4. Add a complete application
  5. Encapsulation support
  6. Hooks and middleware
  7. Restrict middleware execution to a certain path(s)
  8. Wrap Express req in Proxy
  9. TypeScript support
  10. Middleware alternatives
  11. Troubleshooting
  12. POST request with body hangs up
  13. License

@fastify/express

CI NPM version neostandard javascript style

This plugin adds full Express compatibility to Fastify, it exposes the same use function of Express, and it allows you to use any Express middleware or application.

Note This plugin should not be used as a long-term solution, it aims to help you have a smooth transition from Express to Fastify, but you should migrate your Express specific code to Fastify over time.
Since Express does not support Node.js core HTTP/2 module, this plugin does not support HTTP/2 either.

Install

npm i @fastify/express

Compatibility

Plugin versionFastify version
>=4.x^5.x
>=2.x <4.x^4.x
^1.x^3.x
^0.x^2.x

Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin in the table above. See Fastify's LTS policy for more details.

Usage

Register the plugin and start using your Express middlewares.

const Fastify = require('fastify')

async function build () {
  const fastify = Fastify()
  await fastify.register(require('@fastify/express'))
  // do you know we also have cors support?
  // https://github.com/fastify/fastify-cors
  fastify.use(require('cors')())
  // express.Application is also accessible
  fastify.express.disabled('x-powered-by') // true
  return fastify
}

build()
  .then(fastify => fastify.listen({ port: 3000 }))
  .catch(console.log)

Add a complete application

You can register an entire Express application and make it work with Fastify. Remember, @fastify/express is just express under the covers and requires the same body parsers as you'd use in express.

// index.js
const fastify = require('fastify')()
const express = require('express')
const router = express.Router()

router.use(function (req, res, next) {
  res.setHeader('x-custom', true)
  next()
})

router.get('/hello', (req, res) => {
  res.status(201)
  res.json({ hello: 'world' })
})

router.get('/foo', (req, res) => {
  res.status(400)
  res.json({ foo: 'bar' })
})

router.patch('/bar', (req, res) => {
  if (!req.body || Object.keys(req.body).length === 0) {
    res.status(400)
    res.json({ msg: 'no req.body'})
  } else {
    res.status(200)
    res.json(req.body)
  }
})

router.use('*', (req, res) => {
  res.status(404)
  res.json({ msg: 'not found'})
})

fastify.register(require('@fastify/express'))
  .after(() => {
    fastify.use(express.urlencoded({extended: false})) // for Postman x-www-form-urlencoded
    fastify.use(express.json())

    fastify.use(router)
  })

fastify.listen({ port: 3000 }, console.log)

Testing Your App

Run node index.js to start your server. Then run the following commands to ensure your server is working. Use the optional -v flag in curl for verbose output.

me@computer ~ % curl -X GET http://localhost:3000/hello
{"hello":"world"}%
me@computer ~ % curl -X GET http://localhost:3000/foo
{"foo":"bar"}%
me@computer ~ % curl -X GET http://localhost:3000/bar
{"msg":"not found"}%
me@computer ~ % curl -X PATCH -H 'content-type:application/json' http://localhost:3000/bar
{"msg":"no req.body"}%
me@computer ~ % curl -X PATCH -H 'content-type:application/json' -d '{"foo2":"bar2"}' http://localhost:3000/bar
{"foo2":"bar2"}%

Encapsulation support

The encapsulation works as usual with Fastify, you can register the plugin in a subsystem and your express code will work only inside there, or you can declare the express plugin top level and register a middleware in a nested plugin, and the middleware will be executed only for the nested routes of the specific plugin.

Register the plugin in its own subsystem:

const fastify = require('fastify')()

fastify.register(subsystem)

async function subsystem (fastify, opts) {
  await fastify.register(require('@fastify/express'))
  fastify.use(require('cors')())
}

Register a middleware in a specific plugin:

const fastify = require('fastify')()

fastify
  .register(require('@fastify/express'))
  .register(subsystem)

async function subsystem (fastify, opts) {
  fastify.use(require('cors')())
}

Hooks and middleware

Every registered middleware will be run during the onRequest hook phase, so the registration order is important. Take a look at the Lifecycle documentation page to understand better how every request is executed.

const fastify = require('fastify')()

fastify
  .register(require('@fastify/express'))
  .register(subsystem)

async function subsystem (fastify, opts) {
  fastify.addHook('onRequest', async (req, reply) => {
    console.log('first')
  })

  fastify.use((req, res, next) => {
    console.log('second')
    next()
  })

  fastify.addHook('onRequest', async (req, reply) => {
    console.log('third')
  })
}

Restrict middleware execution to a certain path(s)

If you need to run a middleware only under certain path(s), just pass the path as the first parameter to use and you are done!

const fastify = require('fastify')()
const path = require('node:path')
const serveStatic = require('serve-static')

fastify
  .register(require('@fastify/express'))
  .register(subsystem)

async function subsystem (fastify, opts) {
  // Single path
  fastify.use('/css', serveStatic(path.join(__dirname, '/assets')))

  // Wildcard path
  fastify.use('/css/*', serveStatic(path.join(__dirname, '/assets')))

  // Multiple paths
  fastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
}

Note: In prefixed plugins, @fastify/express rewrites string, array, and RegExp mount paths to include the prefix. RegExp paths with ^ anchors inside groups (e.g., /(?:^\/a|^\/b)/) are not rewritten correctly. Use array paths instead: fastify.use(['/a', '/b'], middleware).

Wrap Express req in Proxy

It is possible to wrap the Express request object in a Proxy by passing createProxyHandler function to generate the Proxy handler. The function will receive the Fastify request object as the first parameter.

For example, using Proxy to expose something from Fastify request into the Express request.

fastify.decorateRequest('welcomeMessage', 'Hello World');
fastify.register(expressPlugin, {
  createProxyHandler: fastifyRequest => ({
    get (target, prop) {
      if (prop === 'welcomeMessage') {
        return fastifyRequest[prop]
      }

      return target[prop]
    }
  })
})

TypeScript support

To use this module with TypeScript, make sure to install @types/express.

You will need to add "types": ["@fastify/express"] to your tsconfig.json file when using require to import the plugin.

Middleware alternatives

Fastify offers some alternatives to the most commonly used middleware:

Express MiddlewareFastify Plugin
helmet@fastify/helmet
cors@fastify/cors
serve-static@fastify/static

Troubleshooting

POST request with body hangs up

body-parser library incompatible with fastify-express, when you have fastify routes and any express middlewares. Any POST requests with body, which body-parser will try to parse, will hang up.

Example application:

const Fastify = require('fastify')
const Express = require('express')
const expressPlugin = require('@fastify/express')
const bodyParser = require('body-parser')

const fastify = Fastify()
const express = Express()

express.use(bodyParser.urlencoded({ extended: false }))

await fastify.register(expressPlugin)

fastify.use(express)

// this route will never reply
fastify.post('/hello', (req, reply) => {
  return { hello: 'world' }
})

For this case, you need to remove body-parser, install @fastify/formbody and change @fastify/express options:

const Fastify = require('fastify')
const Express = require('express')
const expressPlugin = require('@fastify/express')
const fastifyFormBody = require('@fastify/formbody')

const fastify = Fastify()
const express = Express()

await fastify.register(fastifyFormBody)
await fastify.register(expressPlugin, {
  // run express after `@fastify/formbody` logic
  expressHook: 'preHandler'
})

fastify.use(express)

// it works!
fastify.post('/hello', (req, reply) => {
  return { hello: 'world' }
})

License

Licensed under MIT.
express license

版本与发布记录

@fastify/express 共发布 21 个版本,首次发布于 2022/04/27;过去 12 个月发布了 7 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.0.9latest2026/10/2718 天前
4.0.82026/10/051 个月前
4.0.72026/06/304 个月前
4.0.62026/05/245 个月前
4.0.52026/04/156 个月前
4.0.42026/01/179 个月前

其他发布通道:next → 4.0.0。

关于 @fastify/express 的常见问题

@fastify/express 是什么?

Express compatibility layer for Fastify

如何安装 @fastify/express?

在项目目录运行 npm install @fastify/express,或使用 pnpm add / yarn add / bun add。

@fastify/express 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fastify/express 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@fastify/express 可以商用吗?

@fastify/express 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fastify/express 的下载量有多少?

根据 npm 官方下载统计,@fastify/express 在 2026/10/15 – 2026/11/13 这 30 天内被下载 396,688 次,日均约 13,223 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fastify/express 还在维护吗?

最新版本 4.0.9 发布于 2026/10/27(18 天前);至今共发布 21 个版本,其中过去 12 个月发布了 7 个;首次发布于 2022/04/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。