Skip to main content

Basic Configuration

NestLens provides a flexible configuration system that allows you to customize its behavior to suit your application's needs. This guide covers the basic configuration options available.

NestLensConfig Interface​

The main configuration interface for NestLens is NestLensConfig, which provides options for controlling the overall behavior of the monitoring system.

interface NestLensConfig {
enabled?: boolean;
path?: string;
trustProxy?: boolean; // honour X-Forwarded-Prefix, off by default
server?: DashboardServerConfig; // a listener of its own; absent by default
authorization?: AuthorizationConfig;
storage?: StorageConfig;
pruning?: PruningConfig;
rateLimit?: RateLimitConfig | false; // disabled by default
security?: SecurityConfig; // data masking + input validation
watchers?: WatchersConfig;
filter?: (entry: Entry) => boolean | Promise<boolean>;
filterBatch?: (entries: Entry[]) => Entry[] | Promise<Entry[]>;
}

Core Options​

enabled​

Controls whether NestLens is active in your application.

  • Type: boolean
  • Default: true
NestLensModule.forRoot({
enabled: true, // NestLens is active
});

You can conditionally enable NestLens based on your environment:

NestLensModule.forRoot({
enabled: process.env.NODE_ENV === 'development',
});

path​

Defines the base URL path where the NestLens dashboard and API will be accessible.

  • Type: string
  • Default: '/nestlens'
NestLensModule.forRoot({
path: '/nestlens', // Dashboard at http://localhost:3000/nestlens
});

Custom path example:

NestLensModule.forRoot({
path: '/admin/monitoring', // Dashboard at http://localhost:3000/admin/monitoring
});

The internal API moves with the dashboard, so every endpoint stays under the same prefix:

PathServes
/admin/monitoringDashboard
/admin/monitoring/__nestlens__/api/*REST API
/admin/monitoring/__nestlens__/streamSSE live-tail

Working with a global prefix​

app.setGlobalPrefix() applies to NestLens too, so the dashboard follows your prefix. No configuration is needed — just remember where it lands:

app.setGlobalPrefix('api');
// Dashboard at http://localhost:3000/api/nestlens

Combined with a custom path, both segments stack:

app.setGlobalPrefix('api');
NestLensModule.forRoot({ path: '/dev/nestlens' });
// Dashboard at http://localhost:3000/api/dev/nestlens

If you would rather keep NestLens off the prefix, exclude it:

app.setGlobalPrefix('api', {
exclude: [{ path: 'nestlens{/*path}', method: RequestMethod.ALL }],
});
// Dashboard stays at http://localhost:3000/nestlens

NestLens is also excluded from URI versioning — app.enableVersioning() will not move the dashboard to /v1/nestlens, so its URL stays put across version bumps.

trustProxy​

Honours the X-Forwarded-Prefix header when building the dashboard's asset and API URLs.

  • Type: boolean
  • Default: false

You need this only when a reverse proxy strips a path segment before forwarding to your application. With this nginx configuration the browser is at /tools/nestlens while your application only ever sees /nestlens:

location /tools/ {
proxy_pass http://app:3000/;
proxy_set_header X-Forwarded-Prefix /tools;
}

Nothing inside the application can detect that rewrite, so without the header the dashboard points its assets at /nestlens/assets/* — a path the proxy does not serve. The page loads blank while the API keeps working.

NestLensModule.forRoot({ trustProxy: true });
// With X-Forwarded-Prefix: /tools → dashboard resolves against /tools/nestlens

The same applies to a Kubernetes ingress that rewrites the path:

annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/x-forwarded-prefix: /tools

:::warning Enable this only behind a proxy that sets the header itself

X-Forwarded-Prefix can be sent by anyone. NestLens ignores values that are not plain absolute paths — a scheme, a host, //, .., a query string or markup is dropped rather than sanitised — but a proxy that forwards a client-supplied header still lets a request influence where the dashboard resolves its URLs, and a shared cache in front of your application could serve that response to others.

Leave trustProxy off unless your proxy overwrites the header on every request, and no path segment is being stripped otherwise.

:::

If your proxy does not rewrite the path — it forwards /nestlens unchanged — you do not need this option at all.

server​

Serves the dashboard on a listener NestLens owns, bound to an address you choose, instead of mounting it on your application's HTTP server.

  • Type: { host: string; port: number }
  • Default: absent — the dashboard mounts on your application, as it always has
NestLensModule.forRoot({
server: { host: '127.0.0.1', port: 3001 },
});
// Dashboard at http://127.0.0.1:3001/nestlens
// http://your-app:3000/nestlens is a 404 — the route is not registered there

host has no default on purpose. Bind it to a private interface — a VPN or tailnet address, a container network, loopback behind an SSH tunnel — and the dashboard is not on the public interface at all, rather than on it and guarded. 0.0.0.0 is a valid answer where the network is the boundary; it just has to be written down.

If the address cannot be bound, the application fails to start. There is no fallback to mounting on your application, because a silent fallback is how a private dashboard becomes a public one.

Authorization is unaffected — allowedIps, canAccess, requiredRoles and the rest are enforced on this listener too.

See Network Isolation for the full picture.

Watchers Configuration​

Watchers are the core monitoring components that collect data about different aspects of your application. Each watcher can be enabled/disabled individually and configured with specific options.

Basic Watcher Control​

You can enable or disable watchers using boolean values:

NestLensModule.forRoot({
watchers: {
request: true, // Monitor HTTP requests (enabled by default)
query: true, // Monitor database queries (enabled by default)
exception: true, // Monitor exceptions (enabled by default)
log: true, // Monitor logs (enabled by default)
cache: false, // Monitor cache operations (disabled by default)
event: false, // Monitor events (disabled by default)
job: false, // Monitor queue jobs (disabled by default)
schedule: false, // Monitor scheduled tasks (disabled by default)
mail: false, // Monitor emails (disabled by default)
httpClient: false, // Monitor outgoing HTTP requests (disabled by default)
redis: false, // Monitor Redis operations (disabled by default)
model: false, // Monitor model operations (disabled by default)
notification: false, // Monitor notifications (disabled by default)
view: false, // Monitor view rendering (disabled by default)
command: false, // Monitor CQRS commands (disabled by default)
gate: false, // Monitor authorization gates (disabled by default)
batch: false, // Monitor batch operations (disabled by default)
dump: false, // Monitor dump/debug operations (disabled by default)
graphql: false, // Monitor GraphQL operations (disabled by default)
},
});

Advanced Watcher Configuration​

For more control, you can pass configuration objects to individual watchers:

NestLensModule.forRoot({
watchers: {
request: {
enabled: true,
ignorePaths: ['/health', '/metrics'],
captureHeaders: true,
captureBody: true,
captureResponse: true,
maxBodySize: 65536, // 64KB
},
query: {
enabled: true,
slowThreshold: 100, // Log queries slower than 100ms
ignorePatterns: [/^SELECT 1$/],
},
exception: {
enabled: true,
ignoreExceptions: ['NotFoundException'],
},
log: {
enabled: true,
minLevel: 'warn', // Only capture warnings and errors
},
},
});

Entry Filtering​

NestLens provides two filtering mechanisms to control which entries are collected:

Single Entry Filter​

Process entries one at a time:

NestLensModule.forRoot({
filter: (entry: Entry) => {
// Skip health check requests
if (entry.type === 'request' && entry.payload.path === '/health') {
return false;
}
return true;
},
});

Batch Filter​

Process multiple entries at once for better performance:

NestLensModule.forRoot({
filterBatch: (entries: Entry[]) => {
// Keep only errors and slow queries
return entries.filter(entry => {
if (entry.type === 'exception') return true;
if (entry.type === 'query' && entry.payload.duration > 1000) return true;
return false;
});
},
});

Complete Configuration Example​

Here's a comprehensive configuration example combining all basic options:

import { Module } from '@nestjs/common';
import { NestLensModule } from 'nestlens';

@Module({
imports: [
NestLensModule.forRoot({
// General settings
enabled: process.env.NODE_ENV !== 'production',
path: '/nestlens',

// Authorization
authorization: {
allowedEnvironments: ['development', 'local', 'test'],
environmentVariable: 'NODE_ENV',
allowedIps: ['127.0.0.1', '192.168.1.*'],
},

// Storage (memory is default, no config needed)
storage: {
driver: 'sqlite',
sqlite: { filename: '.cache/nestlens.db' },
},

// Pruning
pruning: {
enabled: true,
maxAge: 24, // Keep data for 24 hours
interval: 60, // Run pruning every 60 minutes
},

// Rate limiting
rateLimit: {
windowMs: 60000, // 1 minute window
maxRequests: 100, // 100 requests per minute
},

// Watchers
watchers: {
request: {
enabled: true,
ignorePaths: ['/health', '/metrics'],
captureHeaders: true,
captureBody: true,
captureResponse: true,
captureUser: true,
captureSession: true,
},
query: {
enabled: true,
slowThreshold: 100,
},
exception: true,
log: {
enabled: true,
minLevel: 'warn',
},
cache: true,
event: true,
httpClient: {
enabled: true,
ignoreHosts: ['localhost'],
sensitiveHeaders: ['authorization', 'x-api-key'],
sensitiveRequestParams: ['password', 'creditCard'],
sensitiveResponseParams: ['accessToken', 'apiKey'],
},
},

// Entry filtering
filter: (entry) => {
// Skip internal health checks
if (entry.type === 'request' && entry.payload.path?.startsWith('/internal')) {
return false;
}
return true;
},
}),
],
})
export class AppModule {}

Next Steps​

For detailed information about specific configuration areas: