DEV Community

Amis
Amis

Posted on • Edited 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.

Top comments (4)

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

Collapse
 
manssorr profile image
Mansour Koura

Very helpful, Thanks

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.