# How to Debug workerd Applications Using the V8 Inspector Protocol: A Complete Guide

> Debug workerd applications effectively using the V8 Inspector Protocol. Learn to attach Chrome DevTools or VS Code to inspect JavaScript state and set breakpoints in real time.

- Repository: [Cloudflare/workerd](https://github.com/cloudflare/workerd)
- Tags: how-to-guide
- Published: 2026-03-18

---

**To debug workerd applications using the V8 inspector protocol, launch the runtime with `--inspect` or `--inspect-brk`, then attach Chrome DevTools or VS Code to the printed WebSocket URL to set breakpoints and inspect JavaScript state in real time.**

The **cloudflare/workerd** runtime embeds the V8 JavaScript engine and exposes the standard V8 Inspector protocol, allowing you to debug workerd applications using familiar browser and IDE tools. This capability is implemented in the **jsg** layer—the C++ glue that connects V8 to workerd's runtime—and supports the Node.js-compatible debugging API. Whether you are troubleshooting request handlers or inspecting Durable Object state, the inspector gives you direct access to the V8 isolate running your code.

## How the V8 Inspector Protocol Works in workerd

The inspector implementation lives in [`src/workerd/jsg/inspector.h`](https://github.com/cloudflare/workerd/blob/main/src/workerd/jsg/inspector.h) and `src/workerd/jsg/inspector.c++`. When you start a worker with debugging enabled, workerd creates an **`Inspector`** object that registers a V8 `v8_inspector::V8Inspector` client and opens a WebSocket endpoint.

Key architectural details:

- **WebSocket endpoint**: The inspector exposes a JSON-RPC over WebSocket interface (e.g., `ws://127.0.0.1:9229/<uuid>`) that follows the standard Chrome DevTools Protocol (CDP).
- **Isolate lifecycle**: Because workerd creates short-lived isolates per request, the inspector automatically disconnects when the isolate is destroyed, preventing stale connections.
- **JSG integration**: Native resources held by JSG objects are visible in the debugger, allowing you to inspect `Request` and `Response` objects alongside JavaScript variables.

## Enabling the Inspector on Startup

You can activate the inspector using command-line flags or configuration files.

**Command-line flags:**

- **`--inspect=<host>:<port>`** – Starts the inspector and binds to the specified address.
- **`--inspect-brk=<host>:<port>`** – Starts the inspector and pauses execution on the first line of the script, allowing you to set breakpoints before any code runs.

```bash

# Start workerd with inspector on port 9229

workerd --inspect=0.0.0.0:9229 my-worker.wd-config

# Output includes: ws://127.0.0.1:9229/abcd1234

```

**Configuration file method:**

In a `.wd-test` file, set the `inspect` field to enable debugging for automated tests:

```capnp

# src/workerd/api/node/tests/inspector-nodejs-test.wd-test

const config :Workerd.Config = (
  services = [
    ( name = "main",
      worker = (
        modules = [
          ( name = "worker", esModule = embed "inspector-nodejs-test.js" )
        ],
        compatibilityDate = "2023-10-01",
        # Enable inspector for this test

        inspect = "127.0.0.1:9229"
      )
    )
  ]
);

```

## Connecting Your Debugger

Once workerd prints the WebSocket URL, you can attach any V8-compatible debugger.

**Chrome DevTools:**

1. Open `chrome://inspect` in your browser.
2. Click **"Open dedicated DevTools for Node"**.
3. Paste the WebSocket URL (e.g., `ws://127.0.0.1:9229/abcd1234`) into the connection dialog.

**VS Code:**

Use the **"Attach to Node Process"** configuration and specify the port:

```json
{
  "type": "node",
  "request": "attach",
  "name": "Attach to workerd",
  "port": 9229,
  "restart": true
}

```

## Setting Breakpoints and Inspecting State

With the debugger attached, you can control execution and inspect runtime state.

**Programmatic breakpoints:**

Insert the `debugger;` statement in your worker code to force a pause when the inspector is connected:

```javascript
// index.js
export default {
  async fetch(request, env) {
    debugger;  // Execution pauses here when inspector is attached
    const data = await env.MY_KV.get("key");
    return new Response(data);
  }
};

```

**Runtime inspection capabilities:**

- **Call stack**: View the async stack trace through workerd's event loop.
- **Variables**: Inspect local variables, closure state, and global objects.
- **Evaluation**: Execute arbitrary JavaScript expressions in the context of the paused frame.
- **Native bindings**: Examine JSG-wrapped objects like `Request`, `Response`, and `Headers` to see their internal C++ state.

## Node.js Compatibility Layer

workerd exposes Node.js-compatible debugging APIs through [`src/node/inspector.ts`](https://github.com/cloudflare/workerd/blob/main/src/node/inspector.ts). This facade provides the `process` object properties that Node.js developers expect:

- `process.debugPort` – Returns the active inspector port.
- `process._debugProcess()` – Allows programmatic attachment.

This compatibility ensures that debugging tools designed for Node.js (such as the VS Code Node debugger) work seamlessly with workerd without configuration changes.

## Summary

- **workerd** implements the V8 Inspector protocol in `src/workerd/jsg/inspector.c++`, exposing a WebSocket endpoint for debugger attachment.
- Start debugging with **`--inspect`** (run) or **`--inspect-brk`** (pause on first line) flags.
- Connect Chrome DevTools or VS Code to the printed WebSocket URL to step through code and inspect variables.
- The inspector integrates with the **JSG** layer, allowing visibility into both JavaScript heap and native resource objects.
- Automatic cleanup occurs when isolates are destroyed, preventing connection leaks in workerd's request-per-isolate model.

## Frequently Asked Questions

### What is the default port for the workerd inspector?

By default, workerd uses port **9229**, matching Node.js conventions. You can specify any available port using the `--inspect=<host>:<port>` syntax. If the port is omitted, the runtime selects an available ephemeral port and prints the full WebSocket URL to stdout.

### Can I debug multiple workers simultaneously?

Yes, but each worker isolate requires a separate inspector instance with a unique port. Since workerd creates isolates per request or per Durable Object, you must attach the debugger quickly before the isolate completes its work. For long-lived Durable Objects, the inspector connection persists for the lifetime of the object.

### Does the inspector work with Durable Objects?

Absolutely. The V8 inspector protocol works with any JavaScript code running in workerd, including Durable Object methods. You can set breakpoints in `fetch`, `alarm`, or custom methods, and inspect the persistent state stored in the object. The inspector connection remains active as long as the Durable Object isolate exists.

### How do I troubleshoot connection issues?

First, verify that workerd printed the WebSocket URL to stdout, confirming the inspector started. Check that your firewall allows connections to the specified port. If using `--inspect-brk`, ensure you connect the debugger before the script times out waiting for the attachment. Consult the end-to-end test in [`src/workerd/api/node/tests/inspector-nodejs-test.js`](https://github.com/cloudflare/workerd/blob/main/src/workerd/api/node/tests/inspector-nodejs-test.js) for a working reference implementation.