NestJS

NestJS

Scout supports NestJS 10.x+.

1. Install the @scout_apm/scout-apm package:

yarn add @scout_apm/scout-apm

2. Create a scout.ts file and require it before NestJS loads:

// scout.ts
const { init } = require("@scout_apm/scout-apm");

init({
  name: process.env.SCOUT_NAME || "my-nestjs-app",
  key: process.env.SCOUT_KEY,
  monitor: true,
});
// main.ts
import "reflect-metadata"; // safe — no instrumented packages
require("./scout"); // must come before NestJS loads

const { NestFactory } = require("@nestjs/core");
const { AppModule } = require("./app.module");
const { nestMiddleware, nestErrorFilter } = require("@scout_apm/scout-apm");

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(nestMiddleware({ requestTimeoutMs: 0 }));
  app.useGlobalFilters(nestErrorFilter());
  await app.listen(3000);
}

bootstrap();

3. Configure Scout via ENV variables:

export SCOUT_MONITOR=true
export SCOUT_KEY="[AVAILABLE IN THE SCOUT UI]"
export SCOUT_NAME="A FRIENDLY NAME FOR YOUR APP"

If you’ve installed Scout via the Heroku Addon, the provisioning process automatically sets SCOUT_MONITOR and SCOUT_KEY via config vars. Only SCOUT_NAME is required.

4. Deploy.

It takes just a few minutes for your data to first appear within the Scout UI.

Pipeline Instrumentation

Scout automatically creates a sibling span for each guard, pipe, and interceptor under the route’s Controller/{METHOD} {path} span — no code changes required:

@Controller()
class OrdersController {
    @Get("/orders/:id")
    @UseGuards(AuthGuard)
    @UseInterceptors(TimingInterceptor)
    getOrder(@Param("id") id: string) { /* ... */ }
}

produces:

Controller/GET /orders/:id
  ├── NestJS/Guards/AuthGuard
  ├── NestJS/Interceptors/TimingInterceptor
  └── ...route handler...
Span Appears when Name
NestJS/Guards/{Name} Route has one or more guards Guard class name(s), comma-joined if more than one
NestJS/Pipes/{Name} Route has one or more pipes Pipe class name(s)
NestJS/Interceptors/{Name} Route has one or more interceptors Interceptor class name(s)

Unresolvable class names fall back to a generic Guard/Pipe/Interceptor. The interceptor span ends at the next.handle() handoff, so it covers pre-handler work only, not the route handler itself.

Scheduled Jobs (@nestjs/schedule)

@Cron, @Interval, and @Timeout jobs from @nestjs/schedule are each wrapped in their own transaction automatically — no manual BackgroundTransaction needed:

Operation Trigger
NestJS/Schedule/Cron/{jobName} @Cron() decorated method fires
NestJS/Schedule/Interval/{jobName} @Interval() decorated method fires
NestJS/Schedule/Timeout/{jobName} @Timeout() decorated method fires

{jobName} is the method name or explicit decorator name.

Supported Versions

Tested against NestJS 10.x. No runtime version check gates this.