A developer dashboard for NestJS that lives inside your app.
nest-devtools gives you a built-in UI for watching logs and HTTP requests in real time while you develop. It mounts a dashboard route inside your Nest app, stores recent activity in memory, and streams updates over WebSocket with no extra frontend app or external service.
- Why Use It
- Install
- Quick Start
- Configuration
- Ignore Collection With
@IgnoreDevtools() - What The Dashboard Shows
- What Gets Captured
- Routes And Realtime Events
- How It Works
- Production Behavior
- Notes
- Example App
- See Nest logs and HTTP requests in one place while the app is running
- Inspect request bodies, response bodies, headers, status codes, and durations
- Keep the latest entries at the top of the dashboard
- Clear logs or requests from the UI without restarting the app
- Filter noisy traffic globally with typed module options
- Skip collection for specific controllers or handlers with a decorator
- Use it with zero extra infrastructure because everything runs inside the Nest app
npm i nest-devtoolsCompatibility:
- NestJS
^10.0.0 || ^11.0.0 reflect-metadata^0.1.12 || ^0.2.0rxjs^7.8.0
Import the module once in your root module:
import { Module } from '@nestjs/common';
import { DevtoolsModule } from 'nest-devtools';
@Module({
imports: [DevtoolsModule.forRoot()],
})
export class AppModule {}Start your app and open:
http://localhost:3000/__devtools__With the default setup, the dashboard starts collecting:
- Nest logs from
LoggerandConsoleLogger - HTTP requests handled by Nest
- Request body snapshots
- Response body snapshots
- Realtime updates through the built-in WebSocket endpoint
DevtoolsModule.forRoot() accepts typed options:
import { Module } from '@nestjs/common';
import { DevtoolsModule } from 'nest-devtools';
@Module({
imports: [
DevtoolsModule.forRoot({
maxLogs: 1000,
maxRequests: 1000,
path: 'internal/devtools',
capture: {
logs: {
enabled: true,
excludeLevels: ['debug', 'verbose'],
},
requests: {
enabled: true,
excludeMethods: ['OPTIONS', 'HEAD'],
},
},
}),
],
})
export class AppModule {}| Option | Type | Default | Description |
|---|---|---|---|
maxLogs |
number |
500 |
Maximum number of logs kept in memory |
maxRequests |
number |
500 |
Maximum number of requests kept in memory |
path |
string |
__devtools__ |
Base route used for the dashboard, API routes, and WebSocket |
capture |
DevtoolsCaptureOptions |
all capture enabled | Global filters for what gets collected |
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Turn log collection on or off |
excludeLevels |
LogLevel[] |
[] |
Skip selected log levels |
Supported log levels:
logwarnerrordebugverbose
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean |
true |
Turn request collection on or off |
excludeMethods |
HttpMethod[] |
[] |
Skip selected HTTP methods |
Supported HTTP methods:
GETPOSTPUTPATCHDELETEOPTIONSHEADTRACECONNECT
path: '__devtools__'->/__devtools__path: '/inspect/'->/inspectpath: 'internal/devtools'->/internal/devtools
Use @IgnoreDevtools() on a controller class or a route handler when you want devtools to skip collection for that scope.
Import it like this:
import { IgnoreDevtools } from 'nest-devtools';import { Controller, Get, Logger } from '@nestjs/common';
import { IgnoreDevtools } from 'nest-devtools';
@Controller('health')
@IgnoreDevtools()
export class HealthController {
private readonly logger = new Logger(HealthController.name);
@Get()
check() {
this.logger.log('health check');
return { ok: true };
}
}import { Controller, Get, Logger } from '@nestjs/common';
import { IgnoreDevtools } from 'nest-devtools';
@Controller('health')
@IgnoreDevtools({ requests: true })
export class HealthController {
private readonly logger = new Logger(HealthController.name);
@Get()
check() {
this.logger.log('health check');
return { ok: true };
}
}import { Controller, Get, Logger } from '@nestjs/common';
import { IgnoreDevtools } from 'nest-devtools';
@Controller('users')
export class UsersController {
private readonly logger = new Logger(UsersController.name);
@Get('seed')
@IgnoreDevtools({ logs: true })
seedUsers() {
this.logger.log('seed started');
return { ok: true };
}
}Decorator behavior:
@IgnoreDevtools()ignores both logs and requests@IgnoreDevtools({ logs: true })ignores only logs@IgnoreDevtools({ requests: true })ignores only requests- Class-level and method-level ignore options are combined
- Newest log first
- Timestamp
- Level
- Context
- Message
- Client-side search
- Level filters
- Clear action from the UI
- Newest request first
- Timestamp
- HTTP method
- Path
- Status code
- Duration
- Method filters
- Status filters
- Expandable details for headers, request body, and response body
The package captures logs that go through Nest's built-in logging path:
Logger.log()Logger.warn()Logger.error()Logger.debug()Logger.verbose()- direct
ConsoleLoggerusage
Each stored log entry includes:
timestamplevelcontextmessage
The package captures HTTP requests handled by Nest and stores:
timestampmethodpathstatusCodedurationheadersrequestBodyresponseBody
- Request and response bodies are limited to
4kB - JSON, text, arrays, objects, numbers, booleans, and
nullare stored when they fit in the limit - Larger payloads are replaced with a note instead of storing the full body
- Binary payloads are not stored directly
- Uploaded files and binary responses keep metadata instead of raw content
These headers are automatically redacted:
authorizationcookieset-cookieproxy-authorizationx-api-key
- The dashboard's own HTTP requests
- Anything excluded by
capture.logs.excludeLevels - Anything excluded by
capture.requests.excludeMethods - Anything disabled by
capture.logs.enabledorcapture.requests.enabled - Any controller or handler marked with
@IgnoreDevtools() - Any runtime where
NODE_ENV === 'production'
With the default path, the package exposes these routes:
| Method | Path | Description |
|---|---|---|
GET |
/__devtools__ |
Dashboard HTML page |
GET |
/__devtools__/api/logs |
Current log buffer |
GET |
/__devtools__/api/requests |
Current request buffer |
DELETE |
/__devtools__/api/logs |
Clear logs |
DELETE |
/__devtools__/api/requests |
Clear requests |
WS |
/__devtools__/ws |
Realtime stream |
The WebSocket sends these event types:
logrequestclear:logsclear:requests
At runtime, nest-devtools follows this flow:
DevtoolsModule.forRoot()is imported into your Nest app.- The module resolves your options and mounts the dashboard controller.
- A logger capture provider patches Nest's
LoggerandConsoleLoggerflow. - A global request interceptor captures HTTP request and response data.
- Logs and requests are stored in in-memory ring buffers.
- The dashboard page loads the current snapshots from the REST API.
- The browser connects to the built-in WebSocket endpoint for live updates.
- New logs and requests appear at the top of the dashboard as they arrive.
If NODE_ENV === 'production', DevtoolsModule.forRoot() becomes a no-op.
That means:
- no dashboard route
- no API routes
- no WebSocket listener
- no request interceptor
- no logger patching
- Everything is stored in memory only
- Data is cleared when the app restarts
- This package is designed for development, not production monitoring
- If you use a logging library that does not go through Nest's built-in logger path, it will not be captured unless it ultimately calls Nest's logger methods
This repository includes a basic example app:
npm install
npm run example:startThen open:
http://localhost:3000/__devtools__