Back to articles

Configure Sentry on AdonisJS

Introduction

Once you deploy in production your application, it becomes a black box. Errors and performance issues might occur and you will never know unless you actively monitor logs or receive emails from your users complaining.

That's where Sentry comes in.

What is Sentry

Sentry is a SaaS platform that helps track errors and performance issues in your app. It catches crashes, logs API errors, and monitors slow requests, making debugging easier.

It integrates nicely with Github, Slack and Linear and it became a must have on all of my projects.

Sentry Issues

Did you know that Sentry is Open-Source? You can even self-host the platform for free.

Getting Started

Install the Sentry SDK

Run the following command with your favorite package manager to add the Sentry Node SDK to your application:

npm install @sentry/node

Configure Sentry

Sentry has a feature called "auto-instrumentation" that will automatically enable and configure integrations based on your imports. For this to work it has to be the initialized at the very start of your application.

Let's create a file called instrument.ts at the root of our project and initialize Sentry SDK in it:

instrument.ts
import * as  from '@sentry/node'
 
.({
  : '<your-dsn>',
  : 1.0, // You might want to reduce this value in production
})

You get your Sentry DSN when creating a new project or in the settings of an existing one.

Configure Knex integration (optional)

Knex is the underlying library used by Lucid ORM to interact with your database. Which means we can use the Knex integration to monitor our database queries!

instrument.ts
import * as  from '@sentry/node'
 
.({
  : '<your-dsn>',
  : [.()], 
  : 1.0,
})

Initialize Sentry

Let's now import our instrument.ts file at the start of our application. To make sure "auto-instrumentation" works correctly we will do it directly inside our bin/server.ts file.

bin/server.ts
import '../instrument.js'
import 'reflect-metadata'
import { Ignitor, prettyPrintError } from '@adonisjs/core'
 
/**
 * URL to the application root. AdonisJS need it to resolve
 * paths to file and directories for scaffolding commands
 */
const APP_ROOT = new URL('../', import.meta.url)

Capture exceptions

Let's send our first exception to Sentry. After hitting the route / you should see a new issue appearing in your dashboard.

start/routes.ts
import  from '@adonisjs/core/services/router'
import * as  from '@sentry/node'
 
.('/', async () => {
  .(new ('Hello from Adonis'))
  return 'It works!'
})

This is not great as we have to manually capture the exception. Let's change this by directly throwing an error.

start/routes.ts
import  from '@adonisjs/core/services/router'
import * as  from '@sentry/node'
 
.('/', async () => {
  .(new ('Hello from Adonis')) 
  throw new ('Hello again from Adonis') 
  return 'It works!'
})

If you hit the route again, you will not see any issue appearing on your dashboard. This is because Adonis automatically handles exceptions for us. Luckily, we can use the report method on the HttpExceptionHandler to capture exceptions.

app/exceptions/handler.ts
import  from '@adonisjs/core/services/app'
import { ,  } from '@adonisjs/core/http'
import * as  from '@sentry/node'
 
export default class  extends  {
  async (: unknown, : ) {
    .() 
    return super.(, )
  }
}

Now errors thrown in your routes will be automatically captured and sent to Sentry!

Adding User context (optional)

There are a lot of reasons why you would want to attach errors to users. For example, prioritizing issues based on the amount of affected users.

To do this we will create a SilentAuthMiddleware that will authenticate our users even if an auth guard is not configured.

Depending on your starter kit, this middleware might already exist.
app/middleware/silent_auth_middleware.ts
import type {  } from '@adonisjs/core/http'
import type {  } from '@adonisjs/core/types/http'
import * as  from '@sentry/node'
 
export default class  {
  async (: , : ) {
    await .auth.check()
 
    if (.auth.user) {
      const  = .auth.user
      .({
        : .id,
        : .email,
      })
    }
 
    return ()
  }
}

Let's now configure our middleware in start/kernel.ts. Make sure that it is added after the initialize_auth_middleware.

start/kernel.ts
router.use([
  () => import('@adonisjs/core/bodyparser_middleware'),
  () => import('@adonisjs/auth/initialize_auth_middleware'),
  () => import('#middleware/silent_auth_middleware'), 
  () => import('#middleware/initialize_bouncer_middleware'),
])

Conclusion

Setting up Sentry in your AdonisJS app takes few minutes and can save you a ton of time:

  • Monitor errors happening in your application and prioritize them
  • Track performance issues and identify the source of the problem
  • Identify slow database queries thanks to the Knex integration

Now, you’ll always have visibility into what’s happening in production. 🚀

Written by

Martin PAUCOT

At

Wed Apr 02 2025