DEV Community

Amis
Amis

Posted on • Updated on

Fastify plugins

Why plugins?

Fastify let you to plug ( inject ) your dependencies to Fastify instance and then use them wherever you have access to the instance throughout you app. And if you decide to migrate from a monolithic structure to microservices later on, it helps you with that, because every plugin could be a service itself.

What does a plugin look like?

A plugin is just a function that takes in fastify and options as inputs.

This is a plugin:

function pluginA(fastify, options, done) {
    // ...
    done()
}
Enter fullscreen mode Exit fullscreen mode

and this is an async plugin:

async function pluginB(fastify, options) {
    // ...
}
Enter fullscreen mode Exit fullscreen mode

and here is how to register them:

import Fastify from 'fastify'

const fastify = Fastify()

fastify
    .register(pluginA)
    .register(pluginB)
Enter fullscreen mode Exit fullscreen mode

Encapsulation

What encapsulation means is that a copy of Fastify instance is passed to the plugin when you register it. So anything you add to ( decorate ) that instance would only be accessible inside the plugin.

Fastify plugins with encapsulation

import Fastify from 'fastify'

const fastify = Fastify()

fastify
    .register(function pluginA(fastify, options, done) {
        // Add a random number to fastify instance
        fastify.decorate('rand', Math.random())

        console.log(fastify.rand) // Accessible here

        done()
    })
    .register(function pluginB(fastify, options, done) {
        // Try to access the random number added in pluginA
        console.log(fastify.rand) // undefined

        done()
    })
Enter fullscreen mode Exit fullscreen mode

What if you don't want encapsulation? You can use fastify-plugin package to register a plugin to the main Fastify instance.

Fastify plugins without encapsulation

import Fastify from 'fastify'
import fp from 'fastify-plugin'

const fastify = Fastify()

fastify
    // Register pluginA with fastify-plugin
    .register(fp(function pluginA(fastify, options, done) {
        // Add a random number to fastify instance
        fastify.decorate('rand', Math.random())

        console.log(fastify.rand) // Accessible here

        done()
    }))
    .register(function pluginB(fastify, options, done) {
        // Try to access the random number added in pluginA
        console.log(fastify.rand) // Also accessible here

        done()
    })
Enter fullscreen mode Exit fullscreen mode

Packages like fastify-postgres, fastify-mongodb, fastify-redis, ... they all use fastify-plugin so you won't have to register them with fastify-plugin.

Here is the simplified version of fastify-postgres plugin:

const pg = require('pg')
const fp = require('fastify-plugin')

function fastifyPostgres(fastify, options, next) {
    const pool = new pg.Pool(options)
    const db = {
        connect: pool.connect.bind(pool),
        pool: pool,
        Client: pg.Client,
        query: pool.query.bind(pool),
        transact: transact.bind(pool)
    }
    // Inject postgres connection to Fastify instance
    fastify.decorate('pg', db)
    next()
}

module.exports = fp(fastifyPostgres)
Enter fullscreen mode Exit fullscreen mode

How to access registered plugins from route handlers?

Here I used PostgresSQL. I want to be able to use it inside my route handlers to send queries to the database:

// index.js

import Fastify from 'fastify'
import pg from 'fastify-postgres'
import routes from './routes.js'

const fastify = Fastify()

fastify
    .register(pg, {
        connectionString: 'postgres://postgres@localhost/postgres'
    })
    .register(routes)
Enter fullscreen mode Exit fullscreen mode

Here I defined route handlers inside a plugin, so I can access fastify.pg there:

// routes.js

export default function routes(fastify, options, done) {
    fastify.route({
        method: 'GET',
        url: '/',
        handler: (req, reply) => {
            // Have access to fastify.pg here
        }
    })

    done()
}
Enter fullscreen mode Exit fullscreen mode

Here I defined route handlers in a seperate module, so in order to access fastify I need to use the this keyword.

NOTE: Normal functions must be used rather than arrow functions to define route handlers. Read more here.

// routes.js

import { mainHandler } from './handlers.js'

export default function routes(fastify, options, done) {
    fastify.route({
        method: 'GET',
        url: '/',
        handler: mainHandler
    })

    done()
}
Enter fullscreen mode Exit fullscreen mode
// handlers.js

export function mainHandler(req, reply) {
    // Have access to this.pg here
}
Enter fullscreen mode Exit fullscreen mode

End

I recommend you to read the docs if you still have questions about Fastify plugins. You can also join Fastify discord channel, there is a fantastic community there that can help you out.

Latest comments (4)

Collapse
 
ersincol profile image
ERSİN ÇÖL

Although I tried to understand fastify plugin many times, I failed, thank you very much, the resource you wrote was very productive for me.

Collapse
 
manssorr profile image
Mansour Koura

Very helpful, Thanks

Collapse
 
rivanrivaldi21 profile image
rivanrivaldi21

Thanks mate, it's very help me to understand the fastify plugin !

Collapse
 
odili profile image
Chikaodili Chukwunta

Very helpful, Thanks