Set up the profiler
Install @eleven-labs/nest-profiler, enable the core module and inspect your first HTTP requests in the profiler UI.
This tutorial shows how to add @eleven-labs/nest-profiler to a NestJS application and inspect collected request data in the built-in profiler UI.
Step 1 - Install the package
pnpm add @eleven-labs/nest-profiler@alpha nestjs-clsAlpha release
There is no stable release yet — every @eleven-labs/nest-profiler* package must be installed
with the @alpha dist-tag. @latest resolves to nothing.
nestjs-cls is required for per-request context propagation.
Want the profiler in
devDependenciesonly, with no production footprint? Install it withpnpm add -D @eleven-labs/nest-profiler@alpha nestjs-clsand follow the dev-entry split instead of the runtime gate used below.
Step 2 - Register the module
Import ProfilerModule in your root module. The recommended way is to gate it with ConditionalModule.registerWhen, so the profiler loads only when you want it:
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { ConditionalModule } from '@nestjs/config';
const isProfilerEnabled = (env: NodeJS.ProcessEnv) => env['PROFILER_ENABLED'] === 'true';
@Module({
imports: [
ConditionalModule.registerWhen(ProfilerModule.forRoot({ isGlobal: true }), isProfilerEnabled),
],
})
export class AppModule {}If a service injects
ProfilerServicedirectly (customstartSpan, events…), also registerProfilerNoopModule.forRoot({ isGlobal: true })gated on(env) => !isProfilerEnabled(env)so it still resolves when off. Log capture never needs it. See Enabling and disabling.
Step 3 - Enable log capture
Wrap your existing logger in main.ts so log entries appear in the profiler's Logs tab:
import { ConsoleLogger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { createProfilerLogger } from '@eleven-labs/nest-profiler';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bufferLogs: true });
// createProfilerLogger is DI-free — no ProfilerService, and a pass-through when the profiler is off.
app.useLogger(createProfilerLogger(new ConsoleLogger('MyApplication')));
await app.listen(3000);
}
void bootstrap();The capture is logger-agnostic and keeps structured context - message, context name and payload all land in the Logs tab whichever logger the app uses. The Log capture with context tutorial and the Log capture page cover the supported conventions in detail.
Step 4 - Make a request and inspect the profile
Start the application, then make any HTTP request:
curl -i http://localhost:3000/healthThe response includes two headers:
X-Debug-Token: 550e8400-e29b-...
X-Debug-Token-Link: /_profiler/550e8400-e29b-...Open http://localhost:3000/_profiler in your browser to see the list of recent profiles. Click a token to open the detail view with tabs:
- Request - method, URL, headers, query params
- Response - status code, headers
- Performance - duration, memory delta
- Logs - log entries captured during the request
- Exceptions - errors thrown during the request
Step 5 - Secure the profiler (optional)
The profiler is open by default. Restrict /_profiler/* by providing your own security strategy — an authorize predicate and/or NestJS guards. A minimal bearer-token check:
ProfilerModule.forRoot({
security: {
authorize: ({ request }) =>
request.headers['authorization'] === `Bearer ${process.env.PROFILER_TOKEN}`,
},
});PROFILER_TOKEN=my-dev-secret pnpm start:dev
curl -H "Authorization: Bearer my-dev-secret" http://localhost:3000/_profilerSee Securing the UI for basic-auth, cookie/session and DI-guard recipes.
Production warning
Never enable the profiler in production. It exposes internal request data including headers, query parameters, and logs. Disable it in non-development environments.
The recommended way is to gate ProfilerModule with ConditionalModule.registerWhen, so the
active module is never loaded when profiling is off:
import { ProfilerModule } from '@eleven-labs/nest-profiler';
import { ConditionalModule } from '@nestjs/config';
const isProfilerEnabled = (env: NodeJS.ProcessEnv) => env['PROFILER_ENABLED'] === 'true'
ConditionalModule.registerWhen(
ProfilerModule.forRootAsync({ isGlobal: true, useFactory: () => ({ maxProfiles: 100 }) }),
isProfilerEnabled,
),Log capture keeps working when off because createProfilerLogger is DI-free. Only if a service
injects ProfilerService directly do you also register ProfilerNoopModule.forRoot({ isGlobal: true })
gated on (env) => !isProfilerEnabled(env) — it supplies a zero-dependency no-op so the injection
still resolves (every method a no-op; no controller, interceptor, middleware, storage or collector).
Tutorials
Step-by-step NestJS profiler tutorials - enable collectors for SQL, HTTP, GraphQL, cache and auth, and build your own custom collector and entrypoint types.
Log capture with context
Wrap your logger so request-scoped logs - with context names and structured payloads - appear in the profiler's Logs tab.