NestJS Profiler
Packages

nest-profiler-routes

Inspect the application routing table in Symfony-Routing-style Discover views, one per transport.

@eleven-labs/nest-profiler-routes

@eleven-labs/nest-profiler-routes adds the Discover views to the profiler home page — a Symfony-Routing-style view of the application's routing table, with one sidebar view per transport (Discover / HTTP, Discover / GraphQL, Discover / Commands, Discover / RabbitMQ) so each transport's table is a subject of its own. Every registered route is listed with its HTTP method, full path and controller/handler; a lock marks routes protected by a guard. Expanding a route reveals its description, guards, path params, query params, request headers, and the body DTO (class name, decorated properties, TypeScript types and, when class-validator is installed, the validation rules). Non-HTTP sources describe their inputs with their own labels — CLI commands list Arguments and Options with each option's description, GraphQL fields list Arguments.

A transport that discovered nothing gets no view at all, so the sidebar only ever lists what the application actually registered.

Discover / HTTP view — the application routing table with per-route inputs, body DTOs and a lock on guarded routes

Installation

pnpm add -D @eleven-labs/nest-profiler-routes

Peer dependencies: @eleven-labs/nest-profiler. class-validator is an optional peer — install it to surface DTO properties and validation rules; without it, a body DTO shows only its class name.

Setup

profiling/profiling.module.ts
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { RoutesCollectorModule } from '@eleven-labs/nest-profiler-routes';

@Module({
  imports: [ProfilerModule.forRoot({ isGlobal: true }), RoutesCollectorModule.forRoot()],
})
export class ProfilingModule {}

ProfilingModule is the dev-only bundle loaded by main-dev.ts — see Enabling and disabling the profiler. If the profiler is installed as a production dependency behind the runtime gate, wrap the same call in ConditionalModule.registerWhen(..., isProfilerEnabled).

What it collects

At application startup, every registered route is discovered and grouped by transport, and each group becomes its own Discover view — keyed discover-<transport> in the ?view= parameter, so it can never collide with the same-protocol profile list (?view=graphql stays the GraphQL list, ?view=discover-graphql its routing table). The core ships a built-in HTTP source; other transport packages contribute their own — GraphQL resolvers (@eleven-labs/nest-profiler-graphql), RabbitMQ subscribers (@eleven-labs/nest-profiler-rabbitmq) and CLI commands (@eleven-labs/nest-profiler-commander) — by registering a ProfilerDiscoverSource with the core, so they appear automatically when installed.

Each REST route is introspected from its decorator metadata:

  • Guards — the guard classes from @UseGuards() on the controller and/or handler (e.g. an authentication guard); guarded routes show a lock. Only route-level guards are visible — a global APP_GUARD is not attached per handler.
  • Path params — from the route path (/users/:id → id).
  • Query params — from @Query('name') and whole-object @Query() DTOs.
  • Headers — from @Headers('name').
  • Body DTO — from @Body(): the DTO class name, its top-level decorated properties with their TypeScript types, and (with class-validator) the validation rules per property.

Introspection is top-level only: a property that is itself a DTO surfaces as its class name rather than being expanded.

Sources whose inputs are not HTTP-shaped use DiscoverInputs.groups instead — a list of { label, items } sections, each item being a { name, description?, required?, defaultValue? }. That is how the CLI source lists Arguments and Options, and the GraphQL source its field Arguments, without borrowing an HTTP label. A route may also carry a description, rendered above its inputs.

Contributing a custom route source

Any package can add its own Discover view by registering a ProfilerDiscoverSource with the core (mirroring how entrypoint types are registered). Each DiscoverGroup it returns becomes one view; set itemLabel when its entries are not routes, so the count reads 3 commands rather than 3 routes:

import { ModuleRef } from '@nestjs/core';
import { ProfilerCoreService } from '@eleven-labs/nest-profiler';
import type { ProfilerDiscoverSource } from '@eleven-labs/nest-profiler';

// in a module lifecycle hook:
const core = this.moduleRef.get(ProfilerCoreService, { strict: false });
core.registerDiscoverSource(mySource satisfies ProfilerDiscoverSource);

License

MIT © Eleven Labs

Powered & maintained by

On this page