Configuration
The full TelescopeModule.forRoot() options reference — capture, storage, the gate, retention, alerts, AI, CPU profiling, the MCP server, and overload protection.
Every option below is passed to TelescopeModule.forRoot({ … }). All are optional — the defaults give you a zero-config SQLite store, request/exception capture, a production-deny gate, and overload protection. This page is the consolidated reference; each option links out to the concept or recipe that covers it in depth.
Capture & correlation
| Option | Default | Description |
|---|---|---|
enabled | true | Master switch. Compute inline (e.g. NODE_ENV !== 'production'). |
watchers | [] | Built-in + custom watchers (queries, jobs, mail, cache, …). Request and exception capture wire automatically. See Capture. |
extensions | [] | Installable extensions (TelescopeExtension[]) that bundle watchers, a navigable entry type, dashboard pages, and server-side data providers. Additive — extension watchers merge into watchers. See Extensions. |
sampling | none | Per-type keep-fractions for high-volume streams (e.g. { cache: 0.1 }). |
redact | sensible defaults | Deep-redaction of headers / query / body paths plus content bounds (maxDepth, maxStringLength, …). See Performance. |
resolveUser | reads request.user | Resolves the authenticated user recorded on a request entry. |
exceptions | { captureHttp4xx: false } | How thrown exceptions become entries. By default 4xx control flow is not recorded as an exception. See Exception capture. |
exceptions.processCrashes | off | Opt-in capture of unhandledRejection / uncaughtException as exception entries. Attaching these listeners changes whether your process dies, so read the exit contract before enabling. See Process-level crashes. |
requestCapture | 128 KiB cap + binary content-types skipped | Gates a request body before record() sees it — maxBodyBytes, skipBodyContentTypes, skipBody(request). See Request body capture gate. |
registerRequestMiddleware | true | Auto-register request-capture middleware. Set false when using setGlobalPrefix(...) and register capture in bootstrap instead — also exclude Telescope's own routes with telescopeMountPaths() (app.setGlobalPrefix('api', { exclude: telescopeMountPaths() })), or the dashboard/API/assets get shifted under the prefix too. See Request context for your routes. |
Storage & retention
| Option | Default | Description |
|---|---|---|
storage | embedded SQLite | A StorageProvider. Swap for Redis / MikroORM / in-memory. See Storage. |
prune | none | Retention window driving the scheduled pruner (e.g. { after: '24h' }); perType for per-type cutoffs. |
archive | none | Export a type's entries to a sink before the pruner deletes them. See Archiving before prune. |
prune.batchSize | 1000 | Rows per bounded DELETE. A lock-duration knob — see Bounded batched deletes. |
prune.maxBatchesPerCycle | 50 | Hard ceiling on batches per scope per cycle, so a backlog cannot turn one tick into an hour-long loop. |
prune.batchPauseMs | 50 | Pause between batches. Only paid when a second batch is needed, so a healthy store never waits. |
prune.lock | storage lease | Cross-process prune lock, so a fleet prunes once per cycle rather than once per pod. false to opt out, or your own TelescopePruneLock. See Pruning once per fleet. |
prune.lockTtlMs | max(intervalMs * 3, 60s) | Lease TTL — how long the fleet may go unpruned after a holder is killed mid-cycle. |
The gate
| Option | Default | Description |
|---|---|---|
authorizer | deny in production | Gates the read API. Denies in production by default until you supply one. |
authorizeAction | deny | Separate, default-deny gate for mutations — queue actions, Prune now, and request replay. Throwing denies (fails closed). |
dashboardAuth | none | Signed-cookie login for the dashboard. See Dashboard auth. |
guards | none | Bring-your-own CanActivate guard(s) fronting the console's API controllers — appended to (not replacing) the built-in gate above. Pass the SAME guards to TelescopeUiModule.forRoot to also gate the page. See Securing the console. |
imports | [] | Extra Nest imports resolving a class passed to guards' own dependencies. |
clientErrors | { enabled: false } | Public frontend error ingestion. See Reporting frontend errors. |
Health, alerts & AI
| Option | Default | Description |
|---|---|---|
pulse | none | Health-snapshot tuning; slowRouteMs (default 1000) is the p99 a route must reach to count as a slow-request hotspot. |
alerts | none | Pluggable-channel alerting (Slack / webhook / custom) + rules. See Alerts. |
ai | none | AI exception diagnosis. See AI diagnosis. |
profiling | { enabled: false } | On-demand V8 CPU flamegraphs — strictly opt-in. enabled, sampleRate, maxConcurrent, minDurationMs, samplingIntervalMicros. See below and CPU profiling. |
traceContext / traceLink | none | OpenTelemetry trace stamping + deep-link template. See -otel. |
explainQuery | none | Host hook that runs an engine EXPLAIN for a captured query. See Explain slow queries. |
Queues & schedules
| Option | Default | Description |
|---|---|---|
queueManagers | [] | Live queue managers (BullMQ / SQS). A watchers entry that structurally implements the QueueManager SPI (driver, init, listQueues, counts, listJobs, getJob) is auto-registered — this array is only needed for standalone managers that aren't also watchers. See queue managers. |
scheduleManagers | [] | Schedule managers (@nestjs/schedule). Same auto-registration: a watchers entry implementing the ScheduleManager SPI (listTasks) — e.g. ScheduleWatcher — is picked up automatically; listing it in both arrays is safe (deduped by identity, inited once). See the schedule watcher. |
Agents & resilience
| Option | Default | Description |
|---|---|---|
mcp | disabled | MCP server for coding agents. true (dev-only, refused in production), { token } (Bearer-gated everywhere), or omitted/false to disable. See MCP server. |
overloadProtection | true (200ms) | Pause capture under event-loop pressure. See below. |
overloadProtection
overloadProtection?: boolean | { maxEventLoopLagMs?: number; startupGraceMs?: number };Telescope samples the process event-loop delay (perf_hooks.monitorEventLoopDelay) on a 1s interval and, when the p99 lag crosses the threshold, pauses the Recorder (record() becomes a no-op) until the lag recovers — so a telescope under load can never amplify an incident.
true(the default) — protect with a 200ms p99 threshold.false— disable.{ maxEventLoopLagMs }— tune the threshold (defaults to 200 when omitted).{ startupGraceMs }— grace window (default ~5000ms) after the guard arms during which it samples but never pauses or logs, so the synchronous bootstrap stall (DI wiring, migrations, codegen blocking the loop) can't trip the guard on a transient. Set0to arm immediately; ignored when protection is off.
TelescopeModule.forRoot({
overloadProtection: { maxEventLoopLagMs: 100, startupGraceMs: 0 }, // pause sooner, arm at once
});The sampling timer is unref'd (it never keeps the host's loop alive), and the guard degrades to a no-op when perf_hooks.monitorEventLoopDelay is unavailable. See Performance → Overload protection.
profiling
profiling?: {
enabled?: boolean; // default false — master switch
sampleRate?: number; // default 0 — fraction (0–1) auto-captured
maxConcurrent?: number; // default 1 — max simultaneous captures
minDurationMs?: number; // default 0 — discard captures shorter than this
samplingIntervalMicros?: number; // default 1000 — V8 sampling interval
};On-demand V8 CPU flamegraph profiling. Strictly opt-in and OFF by default — while disabled no profiler is constructed, node:inspector is never loaded, and the request path is untouched beyond one boolean check. Enable it for manual "profile the next N requests" captures (via the POST /api/profiles/arm endpoint / the dashboard's Profiles tab), and/or set sampleRate to auto-capture a uniform fraction of traffic.
TelescopeModule.forRoot({
profiling: { enabled: true, sampleRate: 0.01, minDurationMs: 50 },
});Captures are aggregated into a bounded cpu_profile entry (a flame tree, not the raw .cpuprofile) that inherits the profiled request's batch/trace context. Arming is a mutation — behind the default-deny authorizeAction gate. See CPU profiling.
AI exception diagnosis
Add an AI "probable cause" to every exception — a Diagnose with AI button in the dashboard, plus optional auto-mode that enriches new-exception alerts. Works with Bedrock, OpenAI, Anthropic, or any Vercel AI SDK model.
Changelog
Per-package changelogs and the release process — versioned with Changesets, published from CI.