Node.js Debugging Techniques
Debugging is the process of finding and fixing errors, unexpected behavior, or performance issues in code. Even experienced developers spend significant time debugging. Node.js provides several built-in and external tools to make this process systematic and efficient — from simple console output to full interactive debuggers.
Method 1 – console Debugging
The simplest form of debugging is using console methods to inspect values at different points in the code:
function calculateDiscount(price, discount) {
console.log("Input price:", price);
console.log("Input discount:", discount);
const discounted = price - (price * discount / 100);
console.log("Calculated discounted price:", discounted);
return discounted;
}
calculateDiscount(100, 20);
Useful console Methods for Debugging
| Method | Description |
|---|---|
console.log() | Print any value to the terminal. |
console.error() | Print error messages (to stderr stream). |
console.warn() | Print warning messages. |
console.table(data) | Display an array of objects in a formatted table. |
console.dir(obj) | Display an object's full structure, including nested properties. |
console.time('label') | Start a timer. |
console.timeEnd('label') | Stop the timer and print elapsed time. |
console.trace() | Print the current call stack. |
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' }
];
console.table(users); // Displays a clean formatted table
console.time("Sort operation");
users.sort((a, b) => a.name.localeCompare(b.name));
console.timeEnd("Sort operation"); // Output: Sort operation: 0.123ms
Method 2 – Node.js Built-in Debugger
Node.js includes a built-in command-line debugger. Add the inspect flag when starting the script:
node inspect app.js
This opens an interactive debugging session where the following commands are available:
| Command | Action |
|---|---|
n | Step to the next line (step over) |
s | Step into a function call |
o | Step out of the current function |
c | Continue until the next breakpoint |
repl | Enter an interactive REPL to inspect variables |
.exit | Exit the debugger |
Method 3 – Debugging with VS Code (Recommended)
Visual Studio Code provides the best debugging experience for Node.js with a full graphical debugger — no command-line needed.
Setting Up VS Code Debugging
Create a .vscode/launch.json file in the project:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Node.js App",
"program": "${workspaceFolder}/app.js",
"console": "integratedTerminal",
"restart": true,
"runtimeExecutable": "nodemon"
}
]
}
Using the VS Code Debugger
- Open the file in VS Code.
- Click the gutter (left margin) next to a line number to set a breakpoint — a red dot appears.
- Press F5 or go to Run → Start Debugging.
- The program runs until it hits the breakpoint and pauses.
- Inspect variables in the Variables panel on the left.
- Use the debug toolbar to step through code: Step Over, Step Into, Step Out, Continue.
Method 4 – Chrome DevTools for Node.js
Node.js can be debugged using Chrome's browser DevTools:
node --inspect app.js
# Or to pause immediately at the start:
node --inspect-brk app.js
Then open Google Chrome and navigate to: chrome://inspect
Click "Open dedicated DevTools for Node" to get the full Chrome debugger — with breakpoints, call stack, scope variables, and a console — all connected to the Node.js process.
Method 5 – Debugging with the debugger Statement
The debugger keyword acts as a programmatic breakpoint. When the application is run in debug mode, execution pauses at this line:
function processOrder(order) {
debugger; // Execution pauses here when debugging is active
const total = order.price * order.quantity;
return { ...order, total };
}
processOrder({ item: 'Pen', price: 5, quantity: 3 });
When running normally (without debugger tools), the debugger statement is ignored. Remember to remove it before pushing to production.
Method 6 – Error Stack Traces
Reading stack traces is a core debugging skill. When an error occurs, Node.js prints where the error originated and how the call chain led to it:
function c() {
throw new Error("Error in function c");
}
function b() {
c();
}
function a() {
b();
}
a();
Output:
Error: Error in function c
at c (app.js:2:9)
at b (app.js:6:3)
at a (app.js:10:3)
at Object.<anonymous> (app.js:13:1)
Reading from top to bottom: the error occurred in function c, which was called from b, which was called from a. The line numbers point directly to the problem.
Method 7 – Using the util.debuglog() Utility
util.debuglog() creates a conditional logger that only prints output when a specific environment variable is set. This is ideal for adding detailed debug output that can be turned off in production:
const util = require('util');
const debug = util.debuglog('myapp');
function loadConfig() {
debug("Loading configuration file...");
// ... load config
debug("Configuration loaded successfully.");
}
loadConfig();
To enable the debug output, set the NODE_DEBUG environment variable:
NODE_DEBUG=myapp node app.js
Without setting NODE_DEBUG, the debug() calls produce no output at all — perfect for leaving debug logging in the code without it cluttering normal output.
Common Debugging Scenarios
Debugging an Undefined Variable
function getFullName(user) {
console.log("Received user object:", user); // Check what was passed in
return user.firstName + ' ' + user.lastName;
}
getFullName({ firstName: 'Alice' }); // Missing lastName
Debugging an Async Function
async function fetchData(url) {
try {
console.log("Fetching:", url);
const response = await fetch(url);
const data = await response.json();
console.log("Fetched data:", data);
return data;
} catch (err) {
console.error("Fetch failed:", err.message);
}
}
Key Points
console.log(),console.table(), andconsole.time()are the quickest tools for basic debugging.- VS Code's built-in debugger with breakpoints is the most powerful and beginner-friendly debugging tool.
- Chrome DevTools can be connected to a running Node.js process using
node --inspect. - The
debuggerkeyword inserts a programmatic breakpoint — remove it before pushing to production. - Stack traces show exactly where an error occurred and the call chain that led to it — always read them top to bottom.
util.debuglog()enables conditional debug logging that can be toggled on with an environment variable.- Systematic debugging — forming a hypothesis, isolating the problem, testing the fix — is more efficient than guessing.
