Documentation Index Fetch the complete documentation index at: https://mintlify.com/cloudflare/workers-sdk/llms.txt
Use this file to discover all available pages before exploring further.
Debug your Workers using Chrome DevTools, VS Code, and logging tools.
Start Dev Server with Debugging
Wrangler automatically starts an inspector server on port 9229 (or the next available port).
Start wrangler dev
You’ll see: ⎔ Starting local server...
⎔ Debugger listening on ws://127.0.0.1:9229
Click 'inspect'
Under “Remote Target”, click inspect next to your Worker.
Set breakpoints
Open the Sources tab, find your Worker code, and set breakpoints.
Trigger your Worker
Send a request to your Worker: curl http://localhost:8787
Execution pauses at your breakpoints.
Console View console.log() output and errors
Sources Set breakpoints and step through code
Network Inspect fetch requests and responses
Memory Profile memory usage and heap snapshots
VS Code Debugging
Configuration
Create .vscode/launch.json:
{
"version" : "0.2.0" ,
"configurations" : [
{
"name" : "Wrangler Dev" ,
"type" : "node" ,
"request" : "launch" ,
"program" : "${workspaceFolder}/node_modules/.bin/wrangler" ,
"args" : [ "dev" ],
"skipFiles" : [ "<node_internals>/**" ],
"console" : "integratedTerminal"
},
{
"name" : "Attach to Worker" ,
"type" : "node" ,
"request" : "attach" ,
"port" : 9229 ,
"skipFiles" : [ "<node_internals>/**" ]
}
]
}
Start Debugging
Open the Debug panel (Cmd/Ctrl + Shift + D)
Select Wrangler Dev from the dropdown
Click the green play button or press F5
Set breakpoints in your Worker code
Trigger your Worker
Start wrangler dev in a terminal:
Open the Debug panel
Select Attach to Worker
Click the green play button
Set breakpoints and debug
Logging
Console Logging
Standard console methods work in Workers:
export default {
async fetch ( request , env , ctx ) {
console . log ( "Request received:" , request . url );
console . warn ( "Warning: deprecated API used" );
console . error ( "Error occurred" );
console . debug ( "Debug info:" , { request });
return new Response ( "OK" );
}
}
Output appears in:
wrangler dev terminal
Chrome DevTools console
Production logs (via Logpush/Tail Workers)
Structured Logging
function log ( level : string , message : string , data ?: any ) {
console . log ( JSON . stringify ({
timestamp: new Date (). toISOString (),
level ,
message ,
... data
}));
}
export default {
async fetch ( request , env , ctx ) {
log ( "info" , "Request started" , {
url: request . url ,
method: request . method ,
});
try {
const response = await handleRequest ( request , env );
log ( "info" , "Request completed" , {
status: response . status ,
});
return response ;
} catch ( error ) {
log ( "error" , "Request failed" , {
error: error . message ,
stack: error . stack ,
});
throw error ;
}
}
}
Log Levels
Control log verbosity:
wrangler dev --log-level debug
Available levels:
debug - All logs including debug info
info - Informational messages
log - Standard logs
warn - Warnings only
error - Errors only
none - No logs
Or in configuration:
{
"dev" : {
"log_level" : "debug"
}
}
Breakpoint Debugging
Setting Breakpoints
In your code:
export default {
async fetch ( request , env , ctx ) {
// Execution pauses here when debugger is attached
debugger ;
const url = new URL ( request . url );
const path = url . pathname ;
if ( path === "/debug" ) {
// Set a conditional breakpoint here
debugger ;
}
return new Response ( "OK" );
}
}
Or use DevTools to set breakpoints visually.
Conditional Breakpoints
Right-click a line number in DevTools → “Add conditional breakpoint”:
path === "/api" && request . method === "POST"
Watch Expressions
Add watch expressions in DevTools to monitor variables:
request . url
request . headers . get ( "Authorization" )
env . MY_KV
Inspector Configuration
Custom Inspector Port
wrangler dev --inspector-port 9230
Or in configuration:
{
"dev" : {
"inspector" : {
"port" : 9230
}
}
}
Custom Inspector Host
wrangler dev --inspector-ip 0.0.0.0
{
"dev" : {
"inspector" : {
"ip" : "0.0.0.0" ,
"port" : 9229
}
}
}
Disable Inspector
{
"dev" : {
"inspector" : false
}
}
Production Debugging
Tail Workers
Stream real-time logs from production Workers:
For specific events:
wrangler tail --status error
wrangler tail --method POST
wrangler tail --header "User-Agent: *Chrome*"
Sample traffic:
wrangler tail --sampling-rate 0.1 # 10% of requests
Tail Worker Consumers
Create a Worker to process logs:
export default {
async tail ( events , env , ctx ) {
for ( const event of events ) {
console . log ( "Event:" , {
timestamp: event . timestamp ,
outcome: event . outcome ,
logs: event . logs ,
exceptions: event . exceptions ,
});
// Send to external logging service
ctx . waitUntil (
fetch ( "https://logs.example.com" , {
method: "POST" ,
body: JSON . stringify ( event ),
})
);
}
}
}
Configure in wrangler.json:
{
"tail_consumers" : [
{
"service" : "tail-consumer-worker"
}
]
}
Logpush
Forward logs to external services (Enterprise only):
Then configure in the Cloudflare dashboard to send to:
Datadog
New Relic
Splunk
Sumo Logic
S3
Google Cloud Storage
Error Tracking
Capture Errors
export default {
async fetch ( request , env , ctx ) {
try {
return await handleRequest ( request , env );
} catch ( error ) {
// Log error details
console . error ( "Unhandled error:" , {
message: error . message ,
stack: error . stack ,
url: request . url ,
timestamp: Date . now (),
});
// Send to error tracking service
ctx . waitUntil (
fetch ( "https://errors.example.com/report" , {
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({
error: error . message ,
stack: error . stack ,
url: request . url ,
}),
})
);
return new Response ( "Internal Server Error" , { status: 500 });
}
}
}
Integration with Error Services
import * as Sentry from "@sentry/browser" ;
Sentry . init ({
dsn: env . SENTRY_DSN ,
environment: env . ENVIRONMENT ,
});
export default {
async fetch ( request , env , ctx ) {
try {
return await handleRequest ( request , env );
} catch ( error ) {
Sentry . captureException ( error );
throw error ;
}
}
}
async function reportError ( error : Error , context : any ) {
await fetch ( "https://errors.example.com/api/errors" , {
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({
message: error . message ,
stack: error . stack ,
context ,
timestamp: new Date (). toISOString (),
}),
});
}
Timing API
export default {
async fetch ( request , env , ctx ) {
const start = Date . now ();
const response = await handleRequest ( request , env );
const duration = Date . now () - start ;
console . log ( `Request took ${ duration } ms` );
return response ;
}
}
Custom Metrics
function recordMetric ( name : string , value : number , tags ?: Record < string , string >) {
console . log ( JSON . stringify ({
type: "metric" ,
name ,
value ,
tags ,
timestamp: Date . now (),
}));
}
export default {
async fetch ( request , env , ctx ) {
const start = Date . now ();
try {
const response = await handleRequest ( request , env );
recordMetric ( "request.duration" , Date . now () - start , {
status: response . status . toString (),
method: request . method ,
});
return response ;
} catch ( error ) {
recordMetric ( "request.error" , 1 , {
error: error . name ,
});
throw error ;
}
}
}
Debugging Specific Features
Durable Objects
export class Counter {
state : DurableObjectState ;
count : number = 0 ;
constructor ( state : DurableObjectState ) {
this . state = state ;
console . log ( "[DO] Counter initialized" , {
id: state . id . toString (),
});
}
async fetch ( request : Request ) {
console . log ( "[DO] Request received" , {
id: this . state . id . toString (),
url: request . url ,
count: this . count ,
});
this . count ++ ;
await this . state . storage . put ( "count" , this . count );
return new Response ( JSON . stringify ({ count: this . count }));
}
}
Service Bindings
export default {
async fetch ( request , env , ctx ) {
console . log ( "Calling auth service" );
const authResponse = await env . AUTH . fetch ( request );
console . log ( "Auth service response:" , {
status: authResponse . status ,
});
return authResponse ;
}
}
WebSockets
export default {
async fetch ( request , env , ctx ) {
const upgradeHeader = request . headers . get ( "Upgrade" );
if ( upgradeHeader !== "websocket" ) {
return new Response ( "Expected WebSocket" , { status: 400 });
}
const [ client , server ] = Object . values ( new WebSocketPair ());
server . accept ();
server . addEventListener ( "message" , ( event ) => {
console . log ( "WebSocket message:" , event . data );
server . send ( `Echo: ${ event . data } ` );
});
server . addEventListener ( "close" , ( event ) => {
console . log ( "WebSocket closed:" , {
code: event . code ,
reason: event . reason ,
});
});
return new Response ( null , {
status: 101 ,
webSocket: client ,
});
}
}
Best Practices
1. Use Descriptive Logs
// Good
console . log ( "User authentication failed" , {
userId ,
reason: "invalid_token" ,
timestamp: Date . now (),
});
// Bad
console . log ( "error" );
2. Don’t Log Sensitive Data
// Good
console . log ( "Request headers:" , {
contentType: request . headers . get ( "Content-Type" ),
});
// Bad - exposes secrets!
console . log ( "Request headers:" , Object . fromEntries ( request . headers ));
3. Use Log Levels Appropriately
console . debug ( "Detailed debug info" ); // Development only
console . log ( "Request processed" ); // Normal operations
console . warn ( "Deprecated API used" ); // Potential issues
console . error ( "Failed to process" ); // Errors
4. Add Context to Errors
try {
await processRequest ( request );
} catch ( error ) {
console . error ( "Processing failed" , {
error: error . message ,
url: request . url ,
method: request . method ,
timestamp: Date . now (),
});
throw error ;
}
5. Clean Up Debug Code
Use environment variables:
if ( env . DEBUG ) {
console . debug ( "Debug info:" , data );
}
Troubleshooting
Check the inspector port:
wrangler dev --inspector-port 9229
Verify no firewall blocking port 9229
Try a different port:
wrangler dev --inspector-port 9230
Breakpoints Not Hitting
Ensure source maps are enabled (default)
Check that your code is actually running
Verify breakpoint is on an executable line
Clear DevTools cache and reload
Missing Logs
Check log level:
wrangler dev --log-level debug
Ensure console.log() is not commented out
Verify logs appear in DevTools console
See Also
Local Development Develop Workers locally
Testing Test Workers with vitest