Tools

Cloudflare Workers Gets On-Demand CPU and Memory Profiling

Cloudflare now lets you profile Workers and Durable Objects in production, viewing results as interactive flamegraphs to spot resource bottlenecks.

3 min readSource: Cloudflare Blog

Curated by Kandala Guruprasad. Drafted with AI and checked against the source.

Cloudflare Workers Gets On-Demand CPU and Memory Profiling

TL;DR

  • Cloudflare Workers and Durable Objects now support on-demand CPU and memory profiling directly in production via the dashboard or CLI
  • Profiles render as interactive flamegraphs showing which functions consume the most CPU or memory, with the option to download the profile file for further analysis
  • The profiler runs without stopping the Worker by acquiring the isolate lock only for lifecycle operations, allowing normal requests to execute during sampling
  • TypeScript Workers require source maps enabled to avoid seeing obfuscated function names in profiles
Feature
On-demand CPU and memory
Access
Dashboard or CLI (cf package)
Profile format
Interactive flamegraph

What happened

Cloudflare announced support for on-demand CPU and memory profiling of Workers and Durable Objects. From the Workers Observability page, developers can now request an active profile of a running Worker, inspect it as an interactive flamegraph, and download the profile file. This capability enables profiling in production, where requests patterns and traffic volumes most closely reflect real-world application behavior.

How to use it

Profiling is available through two interfaces. Using the CLI, ensure the cf package is installed, then run a profile command specifying the worker ID or name, duration in milliseconds, and profile type. Through the dashboard, navigate to Build → Compute → Workers & Pages, select a Worker, and access its Observability tab to select Flamegraph.

In either case, you specify a duration for how long the profiler runs. The profiler works best on Workers receiving significant traffic, so choose a deployed version with adequate throughput. Once you click Capture Profile, the profiler runs for the selected duration and renders an interactive flamegraph. Each rectangle represents a function call, with width indicating CPU time or memory consumed. Clicking on functions shows details; a table view sorts functions by sample frequency to identify resource-heavy operations quickly.

For TypeScript Workers, enable source maps in your project to avoid obfuscated function names in the results.

bash
cf workers versions profile latest \
--worker-id "$WORKER_ID_OR_NAME" \
--duration-ms 5000 \
--profile-type cpu > worker-cpu.pprof

How it works at the edge

Profiling production Workers poses infrastructure challenges. Workers are replicated across data centers and physical servers, routed to the nearest client location. Before starting a profiling session, the system must determine which version to profile, which data center contains it, whether the isolate remains loaded, and whether it belongs to the requesting account. For Durable Objects, which are stateful and can move, the system must locate the specific live primary actor.

To collect a valid profile without disrupting the Worker, the runtime acquires the isolate lock only for profiler lifecycle operations. For CPU profiling, this means acquiring the lock to start sampling at one millisecond intervals, then releasing it to allow normal requests to run, waiting for the requested duration, reacquiring the lock to stop profiling, and finally releasing it to serialize results. This design prevents the profiler from blocking JavaScript execution during sampling.

Durable Objects benefit from being stateful and named; the runtime can route a profiling request to the specific metal running a named object and profile that exact isolate anywhere in the world. Regular Workers are stateless, so the system picks a running isolate at random.

Real-world examples

Cloudflare's internal teams used profiling to identify optimization opportunities. In one case, a CPU profile of the R2 binding Worker revealed that genericR2JsonReplacer consumed over 5% of CPU time. The function was calling itself recursively while being called by JSON.stringify on every node in the JSON tree, causing values nested multiple levels deep to be processed repeatedly. Fixing this dual-walk eliminated the wasted work and made the function 2.7x faster. Another optimization involved a metrics function called twice in sequence; storing its result and reusing it saved additional CPU time.

Another team used memory profiling to fix frequent out-of-memory errors in production. A heap profile showed that Prometheus instrumentation code accounted for roughly 66.7% of memory allocations, even though the code was supposed to be disabled. The instrumentation was running on enough code paths that it consumed memory proportional to full enablement, despite the collected data never leaving the Worker. Removing the Prometheus code path completely improved P999 memory usage from 133 MB to 118 MB, providing roughly 10 MB of headroom below the 128 MB Worker limit.

Limitations and future work

On-demand profiling has two notable constraints. You must explicitly start each profiling session, which means you may miss important time periods when your Worker misbehaves. The memory profiler captures only allocations occurring during the profiling window, so startup allocations remain invisible. Cloudflare is already working on continuous profiling to address these gaps, capturing profiling samples automatically so developers can explore profiles in the dashboard after the fact, making rare events easier to detect.

Source

Cloudflare Bloghttps://blog.cloudflare.com/workers-on-demand-profiling/

AI-assisted, verified against the source. This post was drafted with AI from the primary source linked above and checked automatically against it. For anything you depend on, read the original.

  • #cloudflare
  • #workers
  • #profiling
  • #performance
  • #observability