How to Use NestJS Graph Inspector for Debugging: A Complete Guide
The NestJS Graph Inspector lets you visualize and export your application's internal dependency graph at runtime, making it easy to detect circular dependencies and understand how providers and modules are wired together.
The Graph Inspector is a built-in diagnostic tool in the nestjs/nest framework that records nodes (modules, providers, controllers) and edges (imports, exports, injections) as your application boots. This guide explains how to enable it, retrieve the graph data, and leverage it for debugging complex dependency hierarchies.
Enabling the Graph Inspector
By default, the Graph Inspector is disabled in production to eliminate overhead. You can activate it either via environment variable or programmatically.
Method 1: Environment Variable
Set the INSPECTOR environment variable to "graph" before starting your application:
# .env
INSPECTOR=graph
Nest will automatically instantiate the GraphInspector class from packages/core/inspector/graph-inspector.ts during bootstrap.
Method 2: Programmatic Registration
For explicit control, pass a GraphInspector instance to the inspect option in NestFactory.create:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: ['error', 'warn', 'log', 'debug', 'verbose'],
inspect: new GraphInspector(),
});
await app.listen(3000);
}
bootstrap();
When disabled, Nest falls back to the NoopGraphInspector located in packages/core/inspector/noop-graph-inspector.ts, which implements the same interface but performs no operations, ensuring zero performance impact.
Retrieving and Visualizing the Dependency Graph
Once enabled, inject the inspector using the APP_INSPECTOR token to access the graph data structure.
Accessing via Controller Endpoint
Create a debug endpoint that exports the graph as JSON:
import { Controller, Get, Inject } from '@nestjs/common';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { APP_INSPECTOR } from '@nestjs/core';
@Controller('debug')
export class GraphController {
constructor(
@Inject(APP_INSPECTOR) private readonly inspector: GraphInspector,
) {}
@Get('graph')
getGraph() {
return this.inspector.getGraph();
}
}
Visiting GET /debug/graph returns a JSON adjacency list:
{
"nodes": [
{ "id": "AppModule", "type": "module" },
{ "id": "UsersService", "type": "provider" }
],
"edges": [
{ "from": "AppModule", "to": "UsersModule", "type": "import" },
{ "from": "UsersService", "to": "DatabaseService", "type": "inject" }
]
}
Pipe this output into visualization tools like Graphviz, D3.js, or Mermaid to generate interactive diagrams of your dependency hierarchy.
Advanced Use Cases
Detecting Circular Dependencies
The graph structure makes back-edges visible. Use a depth-first search (DFS) algorithm to programmatically detect cycles:
import { Injectable, Inject } from '@nestjs/common';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { APP_INSPECTOR } from '@nestjs/core';
@Injectable()
export class CircleDetectorService {
constructor(@Inject(APP_INSPECTOR) private readonly inspector: GraphInspector) {}
findCycles(): string[][] {
const graph = this.inspector.getGraph();
const visited = new Set<string>();
const stack: string[] = [];
const cycles: string[][] = [];
const dfs = (node: string) => {
if (stack.includes(node)) {
const startIdx = stack.indexOf(node);
cycles.push(stack.slice(startIdx).concat(node));
return;
}
if (visited.has(node)) return;
visited.add(node);
stack.push(node);
const outgoing = graph.edges.filter(e => e.from === node);
for (const edge of outgoing) dfs(edge.to);
stack.pop();
};
for (const n of graph.nodes.map(n => n.id)) dfs(n);
return cycles;
}
}
Exporting to Mermaid Format
Convert the graph to Mermaid syntax for documentation:
import { Injectable, Inject } from '@nestjs/common';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { APP_INSPECTOR } from '@nestjs/core';
@Injectable()
export class MermaidGraphService {
constructor(@Inject(APP_INSPECTOR) private readonly inspector: GraphInspector) {}
toMermaid(): string {
const graph = this.inspector.getGraph();
const lines = ['graph TD'];
for (const edge of graph.edges) {
lines.push(` ${edge.from} --> ${edge.to}`);
}
return lines.join('\n');
}
}
Testing with GraphInspector
In integration tests, retrieve the inspector from the module reference to verify your dependency structure:
import { Test } from '@nestjs/testing';
import { AppModule } from '../src/app.module';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { APP_INSPECTOR } from '@nestjs/core';
describe('GraphInspector', () => {
let inspector: GraphInspector;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
inspector = moduleRef.get(APP_INSPECTOR);
});
it('should contain expected nodes', () => {
const graph = inspector.getGraph();
expect(graph.nodes.map(n => n.id)).toContain('UsersService');
});
});
The expected behavior is verified in the framework's own test suites: packages/core/test/inspector/graph-inspector.spec.ts for unit tests and integration/inspector/e2e/graph-inspector.spec.ts for end-to-end scenarios.
Internal Architecture
According to the nestjs/nest source code, the Graph Inspector implements the Inspector contract used by Nest's internal diagnostics subsystem.
- Core Implementation:
packages/core/inspector/graph-inspector.tsdefines theGraphInspectorclass that records module-to-module relationships and provider injections during the instantiation phase. - Data Structure: The inspector maintains a simple adjacency list of nodes and edges that can be serialized to JSON.
- Token Registration: The inspector is registered via the
APP_INSPECTORtoken, allowing you to substitute a custom implementation if needed.
Summary
- The Graph Inspector is disabled by default; enable it via the
INSPECTOR=graphenvironment variable or passinspect: new GraphInspector()toNestFactory.create. - Inject the inspector using the
APP_INSPECTORtoken to retrieve the dependency graph viagetGraph(). - The graph returns nodes (modules, providers, controllers) and edges (imports, exports, injections) as a JSON adjacency list.
- Use the graph to detect circular dependencies, visualize architecture with Mermaid/Graphviz, or verify dependency structure in tests.
- In production, Nest automatically uses
NoopGraphInspectorfrompackages/core/inspector/noop-graph-inspector.tsto ensure zero overhead.
Frequently Asked Questions
How do I enable Graph Inspector in production environments?
You should not enable the Graph Inspector in production. When the INSPECTOR environment variable is unset or empty, Nest automatically substitutes the NoopGraphInspector class, which implements the same interface but performs no operations. This ensures your production builds incur no performance penalty from graph recording.
What data format does Graph Inspector return?
The getGraph() method returns an object with two arrays: nodes (containing id and type fields) and edges (containing from, to, and type fields). This adjacency list format is compatible with standard graph visualization tools like Graphviz, D3.js, and Mermaid, and can be easily serialized to JSON for external analysis.
Can I use Graph Inspector with @nestjs/testing?
Yes. When using Test.createTestingModule(), compile the module reference and retrieve the inspector via moduleRef.get(APP_INSPECTOR). This allows you to verify that your testing module contains expected providers and that dependency relationships are wired correctly during automated testing.
Does Graph Inspector impact application performance?
When enabled, the inspector adds minor overhead during the bootstrap phase as it records each module and provider instantiation. However, when disabled (the default), the framework uses NoopGraphInspector which contains empty methods, resulting in zero runtime impact. Only enable the inspector during development or debugging sessions.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →