Fastify is a framework for backend web development with a powerful plugin architecture and the least overhead. It’s primarily inspired by Hapi and Express and is one of the fastest web frameworks running on Node.js.
Fastify v3.0 is the latest version and has been available since early July 2020. Version 3 has some exceptional new functionalities such as:
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
Now that we’ve covered Fastify’s latest version update functionalities, let’s review a shortlist of Fastify’s most important features:
Depending on code complexity, it can serve around 30,000 requests per second or more for less complex business logic
Hooks, plugins, and decorators make it fully extensible
Internally, Fastify compiles a JSON schema to a highly performant function that can be used for route validation and output serialization
Pino is a highly cost-effective logger used for faster logging
The framework is expressive and easy to get started with. Furthermore, it allows developers to quickly scale small projects to larger performant applications without sacrificing performance or security
The TypeScript type declaration file maintains support to the TypeScript community
Besides the vast amount of features that Fastify offers, it also has a strong plugin architecture. Any developer can build plugins that work with Fastify to create quick building blocks for bootstrapping your API project.
Plugins developed by external developers fall under the category of “community plugins,” while the Fastify team also maintains some plugins of their own, which they label as “core plugins.” However, it’s important to know that any community plugin must adhere to Fastify’s best practices.
The benefit of using core plugins is that the Fastify team actively maintains those plugins, but keep in mind that community plugins may not be maintained.
Here are some important Fastify plugins to note:
And that’s not even a comprehensive list. Fastify has a wide range of plugins to choose from.
Each framework, of course, has its pros and cons — but each framework also has its application. It’s not easy to compare diverse frameworks. However, I tried to select relevant evaluation criteria for when you are choosing a framework.
Here’s an overview of the speed comparison by StackShare.io.
Express: Express processes the least amount of request/sec. The benchmark proves that Express can handle 15,978 requests/sec
Koa: Koa is a better option than Express. It’s also a lightweight framework that handles 54,848 requests/sec
Fastify: Fastify received the best benchmark results with 78,956 requests/sec
As discussed in the previous section, Fastify is the only web framework of these three that has a wide range of plugins, and it makes a major difference. It’s a big plus for developers because they don’t have to rely on multiple frameworks or packages to build their applications. Fastify becomes the one-stop solution.
Again, Fastify is the only framework that has TypeScript support out of the box. Depending on your Node.js version, you may need to install @types/node.
And now, the exciting part! This tutorial will guide you through building your first server with Fastify, covering the following aspects:
Ready? Let’s begin.
First, start a new npm project using:
npm init -y
Next, let’s add the Fastify dependency to your project.
Using npm:
npm i fastify --save
Using yarn:
yarn add fastify
Make sure to have the latest Node.js version installed on your system. You can use nvm (Node Version Manager) for quickly switching between different Node.js versions. You’ll also need a tool to send requests such as cURL or Postman.
Next, let’s create a new file called server.js in the root of your project. Add the following code to your server.js file:
const fastify = require('fastify')({ logger: true })
//Add routes here, discussed in further steps
//@Server
fastify.listen(5000, (err) => {
  if (err) {
    console.log(err)
    process.exit(1)
  } else {
    console.log(`Server running, navigate to  https://localhost:5000`)
  }
})
As you can see, the listen function starts the server on port 5000. It also accepts a callback that accepts one argument, which can contain an error object. This is the most basic server setup for running a Fastify API.
If you want to try out this basic setup, you can use the node command to run the server.js file like this:
node server.js
This will start your server on the address http://localhost:5000. If you try navigating to the address, you’ll see an error that this route doesn’t exist because we haven’t defined any routes yet. Now we’ll need to add some simple CRUD routes.
Let’s add some basic CRUD routes to our application. First, let’s add a GET route.
Imagine we have a stack object that’s a type array. First, we want to add a GET route to retrieve the contents of this array. To do so, we can use the Fastify object to define a get route. The first argument accepts the path we want to attach our route to and the second argument accepts a callback that sends back a reply to your client.
const stack = []
//@Routes
fastify.get('/getStack', (request, reply) => {
  reply.send(stack)
})
Next, let’s try adding items to our stack array using a POST route. This way, we can send data with our request. Here we expect the user to send a JSON object with one parameter called item. We push this item to our stack array. Now we can use the first argument of the callback request, which contains the data being sent with the POST request.
fastify.post('/addItem', (request, reply) => {
    const item = request.body.item
    stack.push(item)
    reply.send(stack)
})
The same principles apply for other route methods such as PUT, DELETE, HEAD, PATCH, and OPTIONS. More information about route options can be found in the Fastify documentation.
Your final routing code should look like this:
const fastify = require('fastify')({ logger: true })
const stack = []
//@Routes
fastify.get('/getStack', (request, reply) => {
  reply.send(stack)
})
fastify.post('/addItem', (request, reply) => {
    const item = request.body.item
    stack.push(item)
    reply.send(stack)
})
//@Server
fastify.listen(5000, (err) => {
  if (err) {
    console.log(err)
    process.exit(1)
  } else {
    console.log(`Server running, navigate to  https://localhost:5000`)
  }
})
Now let’s try out the code we’ve created. First, start the server with node server.js. Next, visit the following route http://localhost:5000/getStack, which should return an empty array object.
Let’s add an item to the stack using cURL. I want to add an apple to the stack. Therefore, I send a JSON object with key item and value apple.
curl --header "Content-Type: application/json" --request POST --data '{"item": "apple"}' http://localhost:5000/addItem
If you visit http://localhost:5000/getStack again, you’ll notice that the stack array is populated with the apple item.
All good? Let’s add a plugin!
To demonstrate how easy it is to add and use a Fastify plugin, let’s install fastify-routes, which enables us to retrieve a map of all registered routes with our Fastify instance.
First, install the Fastify-routes dependency from the CLI:
npm i fastify-routes
After installing the plugin, register the plugin by including it before you register any routes.
Here’s a snippet of the server.js file that includes the fastify-routes plugin. I’ve also added a console.log statement that shows how you can use the plugin to return all registered routes.
const fastify = require('fastify')({ logger: true })
fastify.register(require('fastify-routes')) // Add and register plugin
const stack = []
//@Routes
fastify.get('/getStack', (request, reply) => {
    reply.send(stack)
})
fastify.post('/addItem', (request, reply) => {
    const item = request.body.item
    stack.push(item)
    reply.send(stack)
})
//@Server
fastify.listen(5000, (err) => {
    console.log(fastify.routes) // Log all registered routes
    if (err) {
        console.log(err)
        process.exit(1)
    } else {
        console.log(`Server running, navigate to  https://localhost:5000`)
    }
})
Now when you start the server with node server.js, your CLI prints all registered routes.
This plugin demonstrates how easy it is to add a plugin to your server. You don’t need to initialize them. The fastify object that forms your server also acts as the parent for all the registered plugins, and you can call them directly from this fastify object.
Finally, let’s add some basic data validation to our server.
As the final element in this tutorial, let’s add data validation to your routes. Specifically, we want to add validation for the POST route we created earlier. Let’s validate if the body object contains the item property and the type of data should match a string type.
Luckily, Fastify allows us to define validation schemas for routes. Here’s an example that verifies if the item property is present and contains a string. Furthermore, we tell the Fastify server that we don’t allow any additional properties on the body object using the additionalProperties: false setting.
You can also define a response property that describes the response when the request is successful.
Here’s the full code after adding the data validation options. Do not forget to add the itemValidation as the second argument to the POST route.
const fastify = require('fastify')({ logger: true })
fastify.register(require('fastify-routes'))
const itemValidation = { // Define validation
    schema: {
        body: {
            type: 'object',
            additionalProperties: false,
            required: [
                'item'
            ],
            properties: {
                item: { type: 'string' }
            }
        },
        response: {
            201: {
                type: 'object',
                properties: {
                    item: { type: 'string' }
                }
            }
        }
    }
}
const stack = []
//@Routes
fastify.get('/getStack', (request, reply) => {
    reply.send(stack)
})
fastify.post('/addItem', itemValidation, (request, reply) => { // Add validation options to POST route
    const item = request.body.item
    stack.push(item)
    reply.send(stack)
})
//@Server
fastify.listen(5000, (err) => {
    console.log(fastify.routes)
    if (err) {
        console.log(err)
        process.exit(1)
    } else {
        console.log(`Server running, navigate to  https://localhost:5000`)
    }
})
Let’s try out the code again by sending the same request to our server, adding the apple item. This request should be successfully executed.
curl --header "Content-Type: application/json" --request POST --data '{"item": "apple"}' http://localhost:5000/addItem
Next, let’s try sending an item that contains an empty object so we can test if the server rejects the request. Send the below request to your server to verify the data validation implementation.
curl --header "Content-Type: application/json" --request POST --data '{"item": {}}' http://localhost:5000/addItem
The server should send you the following error message:
{"statusCode":400,"error":"Bad Request","message":"body.item should be string"}
All good? Congratulations! You’ve successfully completed your first Fastify API server.
I hope you enjoyed building a simple CRUD API using Fastify while implementing data validation and adding plugins.
Many more plugins exist, so definitely check out the Fastify plugin ecosystem to see what’s available. Plugins are useful to quickly bootstrap your API, removing the need to build an API from scratch.
Feel free to check out the following concepts Fastify offers:
That’s it, folks! Full code can be found on my GitHub repository.
            Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
            server-side
            
$ npm i --save logrocket 
// Code:
import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
                    
                    
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
                    
                    
AI agents powered by MCP are redefining interfaces, shifting from clicks to intelligent, context-aware conversations.

Learn how platform engineering helps frontend teams streamline workflows with Backstage, automating builds, documentation, and project management.

Build an AI assistant with Vercel AI Elements, which provides pre-built React components specifically designed for AI applications.

line-clamp to trim lines of textMaster the CSS line-clamp property. Learn how to truncate text lines, ensure cross-browser compatibility, and avoid hidden UX pitfalls when designing modern web layouts.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now