Debug a Node.js application
Use targeted logs, Inspector breakpoints, or a VS Code launch configuration, and investigate production failures without exposing a debugger.
Use logs to narrow a problem, then attach a debugger when you need to inspect execution state. Node's Inspector supports breakpoints, stepping, variable inspection, and call stacks through tools such as Chrome DevTools and VS Code.
Start with focused output
const request = { id: 'example-1', state: 'queued' };
console.log('Request state:', request.state);
console.table([request]);
console.time() and console.timeEnd() can measure a selected interval. The debug package provides switchable namespaces; it is not inherently a conventional severity-level system. Keep diagnostic output bounded and omit credentials and sensitive payloads.
Attach Chrome DevTools
node --inspect your-script.js
Open chrome://inspect in Chrome and inspect the detected Node target. The default Inspector endpoint listens on loopback, normally port 9229. If execution finishes before you connect, use:
node --inspect-brk your-script.js
This pauses before user code starts, giving you time to attach and investigate initialization. Set breakpoints, resume execution, and inspect the call stack and local variables.
Add an explicit breakpoint
function calculate(a, b) {
debugger;
return a + b;
}
With an attached debugger configured to pause, the statement provides a convenient breakpoint. It is not a normal logging operation or a production control mechanism. Remove temporary breakpoints when the investigation is complete.
Launch from VS Code
Put a configuration like this in .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug the current file",
"program": "${file}",
"skipFiles": ["<node_internals>/**"]
}
]
}
Open the intended entry file, set a breakpoint, and start debugging. Applications that need a particular working directory, environment, build step, or source maps should use a configuration that represents how they actually run.
Investigate production without pausing requests
Pausing a shared JavaScript thread interrupts the work it handles. Prefer correlated structured logs, diagnostic reports, traces, and profiling appropriate to the incident. --report-on-fatalerror requests a diagnostic report for fatal errors supported by that mechanism, such as an out-of-memory failure; it does not explain every application error automatically. Store reports carefully because they can contain sensitive runtime details.
For Guance, follow the trace and log correlation instructions for the instrumentation in use. Verify the resulting trace identifiers rather than assuming an arbitrary log field will be linked automatically. Uninstrumented operations still need instrumentation.
FAQ
How do inspect and inspect-brk differ? --inspect enables the endpoint while code runs; --inspect-brk pauses before user code begins. The latter is useful for startup problems.
Can I expose the Inspector port? A connected debugger can execute code in the process. Keep access restricted. If remote debugging is justified, use a controlled environment and protected access such as an authenticated tunnel; do not bind an unrestricted public listener.
Why do asynchronous call stacks look different? Work resumes through promises and callbacks. Debugger support for async stacks and source maps can help connect those steps, but it cannot reconstruct every historical or external operation. Use request context in logs alongside the debugger.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan