Skip to main content

Overview

Node.js provides powerful debugging capabilities through the V8 Inspector protocol, enabling you to debug applications using Chrome DevTools, VS Code, and other debugging clients.

Command-Line Debugger

Node.js includes a built-in command-line debugging utility for simple stepping and inspection.

Starting the Debugger

Start Node.js with the inspect argument:
node inspect myscript.js
Output:
< Debugger listening on ws://127.0.0.1:9229/621111f9-ffcb-4e82-b718-48a145fa5db8
< For help, see: https://nodejs.org/en/docs/inspector
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.

Break on start in myscript.js:2
  1 // myscript.js
> 2 global.x = 5;
  3 setTimeout(() => {
  4   debugger;
debug>
The debugger automatically breaks on the first executable line.

Resume on Start

To run until the first debugger statement instead of breaking immediately:
NODE_INSPECT_RESUME_ON_START=1 node inspect myscript.js

Debugger Commands

Stepping Commands

cont, c
command
Continue execution
next, n
command
Step to next line
step, s
command
Step into function
out, o
command
Step out of function
pause
command
Pause running code

Breakpoint Commands

# Set breakpoint on current line
setBreakpoint()
sb()

# Set breakpoint on specific line
setBreakpoint(line)
sb(line)

# Set breakpoint in function
setBreakpoint('fn()')

# Set breakpoint in file
setBreakpoint('script.js', 1)

# Conditional breakpoint
setBreakpoint('script.js', 1, 'num < 4')

# Clear breakpoint
clearBreakpoint('script.js', 1)
cb('script.js', 1)

Information Commands

backtrace, bt
command
Print backtrace of current execution frame
list(5)
command
List source code with 5 line context
watch(expr)
command
Add expression to watch list
watchers
command
List all watchers and their values
repl
command
Open debugger REPL for evaluation
exec expr
command
Execute expression and print value

Using Watchers

Watch expression values at each breakpoint:
// Add a watcher
watch('myVariable')
watch('obj.property')

// List all watchers
watchers

// Remove a watcher
unwatch('myVariable')

REPL Mode

Evaluate code in the debugging context:
debug> repl
Press Ctrl+C to leave debug repl
> x
5
> 2 + 2
4
> myFunction()
'result'
Press Ctrl+C to exit REPL mode.

V8 Inspector Protocol

The V8 Inspector enables powerful debugging with Chrome DevTools and other clients.

Inspector Flags

Start with inspector enabled. Code runs immediately.
node --inspect index.js
Output:
Debugger listening on ws://127.0.0.1:9229/dc9010dd-f8b8-4ac5-a510-c1a114ec7d29
For help, see: https://nodejs.org/en/docs/inspector

Custom Port

Specify a custom debugging port:
node --inspect=9222 index.js
node --inspect=0.0.0.0:9222 index.js  # Listen on all interfaces
Binding the inspector to a public IP:port combination is insecure. Ensure proper firewall rules are in place.

Chrome DevTools Integration

Connecting Chrome DevTools

1

Start Node.js with inspector

node --inspect-brk app.js
2

Open Chrome

Navigate to chrome://inspect in Google Chrome
3

Configure target discovery

Click “Configure” and add localhost:9229 to the target list
4

Inspect

Click “inspect” under your Node.js process

DevTools Features

  • Sources Panel: Set breakpoints, step through code
  • Console: Evaluate expressions in the current context
  • Profiler: Record CPU profiles
  • Memory: Take heap snapshots
  • Network: Inspect network requests (with --experimental-network-inspection)

VS Code Debugging

Launch Configuration

Create .vscode/launch.json:
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/app.js"
    },
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Process",
      "port": 9229,
      "restart": true
    }
  ]
}

Debug Current File

{
  "type": "node",
  "request": "launch",
  "name": "Debug Current File",
  "program": "${file}",
  "skipFiles": ["<node_internals>/**"]
}

Debug with Arguments

{
  "type": "node",
  "request": "launch",
  "name": "Launch with Args",
  "program": "${workspaceFolder}/app.js",
  "args": ["--config", "production.json"],
  "env": {
    "NODE_ENV": "development"
  }
}

Using the Inspector API

Programmatically control the inspector from your code.

Opening the Inspector

const inspector = require('node:inspector');

// Open inspector on default port
inspector.open();

// Open on specific port
inspector.open(9229, 'localhost');

// Wait for debugger to attach
inspector.open(9229, 'localhost', true);

CPU Profiling

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';

const session = new Session();
session.connect();

await session.post('Profiler.enable');
await session.post('Profiler.start');

// Run code to profile
performExpensiveOperation();

const { profile } = await session.post('Profiler.stop');
fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));

Heap Snapshots

import { Session } from 'node:inspector/promises';
import fs from 'node:fs';

const session = new Session();
const fd = fs.openSync('profile.heapsnapshot', 'w');

session.connect();

session.on('HeapProfiler.addHeapSnapshotChunk', (m) => {
  fs.writeSync(fd, m.params.chunk);
});

await session.post('HeapProfiler.takeHeapSnapshot', null);
session.disconnect();
fs.closeSync(fd);

Taking Heap Snapshots from Debugger

From the command-line debugger:
debug> takeHeapSnapshot('snapshot.heapsnapshot')

Debugging Best Practices

Add debugger; statements in your code to create breakpoints:
function processData(data) {
  debugger; // Execution will pause here
  return data.map(item => item * 2);
}
For TypeScript or transpiled code, enable source maps:
node --enable-source-maps dist/app.js
Focus on your code by skipping Node.js internals in VS Code:
{
  "skipFiles": ["<node_internals>/**", "node_modules/**"]
}
Break only when specific conditions are met:
setBreakpoint('app.js', 42, 'user.id === 123')

Remote Debugging

SSH Tunneling

Debug a remote Node.js application securely:
# On remote server
node --inspect=127.0.0.1:9229 app.js

# On local machine
ssh -L 9229:localhost:9229 user@remote-server
Then connect Chrome DevTools to localhost:9229.

Troubleshooting

  • Verify the port is not blocked by firewall
  • Check if another process is using port 9229
  • Ensure you’re connecting to the correct IP/port
  • Enable source maps: --enable-source-maps
  • Ensure source map files (.map) are present
  • Check sourceRoot in tsconfig.json
  • Verify code is actually being executed
  • Check if using —inspect-brk for early breakpoints
  • Ensure file path matches exactly

Next Steps

Performance

Profile and optimize your code

Testing

Write and run tests