NestJS Profiler
Packages

nest-profiler-commander

Profile nest-commander CLI runs alongside HTTP requests.

@eleven-labs/nest-profiler-commander

@eleven-labs/nest-profiler-commander profiles CLI commands built with nest-commander — the console equivalent of Symfony's command profiling. Every command run produces a profile that shows up in the web profiler at /_profiler, in a dedicated Commands table and with a built-in Command tab, plus any HTTP, cache, or database activity the command triggered.

Commands view — every profiled CLI command with its status and duration

Command tab — a profiled nest-commander run with its arguments and options

Installation

pnpm add @eleven-labs/nest-profiler-commander nest-commander

Peer dependencies: nest-commander ^3.20.0

Setup

The collector wraps every discovered command automatically — you do not change your command classes. Register it in the module you bootstrap with CommandFactory:

cli.module.ts
import { Module } from '@nestjs/common';
import { ConditionalModule } from '@nestjs/config';
import { CommanderCollectorModule } from '@eleven-labs/nest-profiler-commander';
import { AppCommand } from './app.command';

const isProfilerEnabled = (env: NodeJS.ProcessEnv) => env['PROFILER_ENABLED'] === 'true';

@Module({
  imports: [ConditionalModule.registerWhen(CommanderCollectorModule.forRoot(), isProfilerEnabled)],
  providers: [AppCommand],
})
export class CliModule {}

Enabling / disabling — gate the collector with ConditionalModule.registerWhen(..., isProfilerEnabled) as shown, so it loads only when PROFILER_ENABLED is on. Wire the core ProfilerModule once at the CLI root — use storageType: 'file' so the CLI process and the HTTP server share the same profiles. The recommended setup bundles the root-level profiler modules into a single ProfilingModule behind two ConditionalModule gates (see Enabling and disabling the profiler and the example app). A top-level enabled option is also supported as an alternative.

cli.ts
import { CommandFactory } from 'nest-commander';
import { CliModule } from './cli.module';

async function bootstrap(): Promise<void> {
  await CommandFactory.run(CliModule, { logger: ['error', 'warn'] });
}

void bootstrap();

Run a command, then open /_profiler on your HTTP app (pointed at the same storagePath) to inspect it.

Cross-process storage required. The CLI and the web server are separate processes, so command profiles are only visible in the server when both share the backing store — use storageType: 'file' (or a Redis/DB adapter). In-memory storage is per-process; the profiler logs a warning if you profile a command against it.

What it collects

Each command run sets a command entrypoint on the profile (entrypoint.type = 'command', with this payload on entrypoint.data):

FieldDescription
nameCommand name from @Command({ name })
argumentsPositional operands (run(passedParams))
optionsParsed flags (run(_, options))
successWhether the command completed without throwing

arguments and options are two distinct things, and the Command tab shows them as two sections: for mycli demo:greet Grace --name Ada, arguments is ['Grace'] (the positional operands declared by @Command({ arguments })) and options is { name: 'Ada' } (the flags declared by @Option(), with their defaults applied). Both are redacted before storage — CLI values routinely carry secrets (--token=…).

A command that never reached run() is profiled too. nest-commander evaluates the @Option() value parsers while commander parses the argv, so an option parser that rejects its input (throw new Error('Unknown site parameter')) aborts the invocation before the command body runs: the profile records the command with success: false, the options commander had resolved so far (declared defaults included) plus the raw value the rejected flag was given, and the thrown error in the Exceptions tab. Its arguments are empty — commander assigns the positional operands only once every option has parsed.

Not every parse failure can be recorded. Commander handles its own argv errors — an unknown option, a missing required option, an invalid choices value, or an option parser that throws commander's InvalidArgumentError — by printing a CLI error and calling process.exit() itself. The process is gone before any profile can be written, so those runs leave no profile. Throw a plain Error from an option parser to have the failure profiled.

No exit code is collected: the profiler wraps run() from inside the process, so it never observes the code the CLI eventually exits with — it only knows whether the command threw, which success already says. Read success (or the profile's response.statusCode, 200 / 500) instead. Duration and timing come from the profile's standard performance data, and a thrown error appears in the Exceptions tab. Because the command body runs inside the profiler's CLS context, profile-scoped collectors (e.g. @eleven-labs/nest-profiler-http, @eleven-labs/nest-profiler-cache) capture the work a command performs and contribute their own panels.

How it works

At application bootstrap the module discovers every provider that is an instance of nest-commander's CommandRunner and wraps its run() method, plus the value parser of each of its @Option() flags (they run earlier, during commander's parse phase, and a throwing parser would otherwise abort the run without producing any profile — a parse failure is persisted through the profiler core's deferred queue, drained at application shutdown, since commander's parse phase is synchronous and cannot await a save). The wrapper synthesises a profile with a command entrypoint (entrypoint.type = 'command', the command details on entrypoint.data), opens a CLS context, runs the original command, then runs all collectors and saves the profile through the profiler's shared storage. The module registers the command entrypoint type with the profiler core, which renders command profiles in a dedicated Commands table and a built-in Command tab — import the module in your HTTP app too so cross-process command profiles render there.

It also contributes the Discover / Commands view (@eleven-labs/nest-profiler-routes), listing every @Command() class with its description and, per command, its positional Arguments (from @Command({ arguments, argsDescription })) and its Options (from @Option({ flags, description, defaultValue, required })) — so the view documents the CLI the same way --help does. nest-commander is a required peer dependency of this package (it imports CommandRunner statically).

Powered & maintained by

On this page