nest-profiler-commander
Types and API of the nest-commander CLI collector.
CommandInfo
Payload of a command profile's entrypoint.data (entrypoint type: 'command'). The module
registers a command entrypoint type, so the profiler renders a dedicated Commands table and a
Command detail tab for these profiles.
Prop
Type
Public exports
import { CommanderCollectorModule } from '@eleven-labs/nest-profiler-commander';
import { CommandProfiler } from '@eleven-labs/nest-profiler-commander';
import { COMMAND_ENTRYPOINT_TYPE } from '@eleven-labs/nest-profiler-commander';
import type { CommanderCollectorModuleOptions } from '@eleven-labs/nest-profiler-commander';
import type { CommandInfo } from '@eleven-labs/nest-profiler-commander';Enabling and disabling
CommanderCollectorModule.forRoot() takes no required options. Gate it per environment with Nest's ConditionalModule so it loads only when the profiler is on — the same pattern used for every profiler module:
import { ConditionalModule } from '@nestjs/config';
const isProfilerEnabled = (env: NodeJS.ProcessEnv) => env['PROFILER_ENABLED'] === 'true'
ConditionalModule.registerWhen(CommanderCollectorModule.forRoot(), isProfilerEnabled),Setup
Register the module in the module you bootstrap with CommandFactory:
import { Module } from '@nestjs/common';
import { ProfilerModule } from '@eleven-labs/nest-profiler';
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 {}Wire the core ProfilerModule (with storageType: 'file' so the CLI and HTTP server share profiles) once at the CLI root — see Enabling and disabling the profiler. If a command injects ProfilerService directly, also register its ProfilerNoopModule fallback.
import { CommandFactory } from 'nest-commander';
import { CliModule } from './cli.module';
async function bootstrap(): Promise<void> {
await CommandFactory.run(CliModule, { logger: ['error', 'warn'] });
}
void bootstrap();Every provider that extends nest-commander's CommandRunner is wrapped automatically - you do not change your command classes.
There is no forRootAsync by design: the collector has no runtime-resolved options (its only knob, enabled, is a synchronous build-time decision), so toggle it per environment with ConditionalModule.registerWhen(...).
Prerequisite: nest-commander installed, and a cross-process storage adapter if you want to inspect command profiles from the HTTP app's web profiler at /_profiler. The CLI and the server are separate processes, so they must share the backing store - use storageType: 'file' (or a Redis/DB adapter). In-memory storage is per-process and can never surface command profiles in a separate web server; the profiler logs a warning when you profile a command against an in-memory store.
How a command profile is shaped
A command has no HTTP request/response. The profiler synthesises a profile whose entrypoint is
{ type: 'command', data: CommandInfo }:
| Field | Value |
|---|---|
entrypoint.type | command |
entrypoint.data.name | The command name (e.g. content:sync) |
entrypoint.data.arguments | The positional arguments |
entrypoint.data.exitCode | 0 on success, 1 when the command threw |
response.statusCode | 200 on success, 500 when the command threw |
The command name, arguments, options, and exit code are kept on entrypoint.data. Because the command body runs inside the profiler's CLS context, profile-scoped collectors (HTTP client, cache, database, …) capture the work the command performs and contribute their own panels.