By ITCuli

Introducing on-demand CPU and memory profiling with flamegraphs for Workers and Durable Ob

Introducing on-demand CPU and memory profiling with flamegraphs for Workers and Durable Ob

Cloudflare has introduced on-demand CPU and memory profiling for Workers and Durable Objects. The capability is available from the Workers Observability experience and through the cf CLI. Its practical value is simple: administrators can capture evidence from live execution instead of inferring causes from logs and aggregate metrics alone.

A profile is rendered as an interactive flamegraph. Every rectangle represents a function call; its width represents the CPU time or memory attributed to that function. Engineers can click into a call path, hover for details, use the table view, and download the profile for further work. This turns a vague “the Worker is slow” or “memory is rising” report into a ranked list of real functions and allocations.

Cloudflare Workers flamegraph interface

What is new and how to start

In the dashboard, open Build → Compute → Workers & Pages, choose a Worker, open Observability, then choose Flamegraph. Select CPU or memory, select the deployed version, set a capture duration, and press Capture Profile. The selected version must have enough traffic: Cloudflare does not start a new isolate just to manufacture a profile, because the feature is intended to observe production behavior.

The equivalent CLI workflow uses the cf package. A CPU capture can be started with cf workers versions profile latest --worker-id "$WORKER_ID_OR_NAME" --duration-ms 5000 --profile-type cpu > worker-cpu.pprof. The resulting file is suitable for further analysis. TypeScript teams should enable source maps; otherwise profiles can display obfuscated function names and make a genuine hot path difficult to identify.

Cloudflare profile capture settings

Concrete production lessons

Cloudflare describes a CPU investigation in the Worker behind the R2 binding. A 50-second capture showed genericR2JsonReplacer consuming more than 5% of CPU time. The function was recursively walking a JSON tree while JSON.stringify also invoked it for every node. A value five levels deep could therefore be processed five times. Removing the duplicate work made that function 2.7 times faster. Another trace exposed a costly duplicate registry.metrics() call; storing the first result avoided a repeated operation that alone represented 1% of CPU time.

The memory example is equally operational. One internal Worker had P999 memory near 133 MB while its limit was 128 MB, producing frequent Exceeded Memory evictions. A heap profile showed Prometheus code responsible for roughly 66.7% of allocations even though the team believed it was disabled. Removing that still-active path reduced P50 from 70 MB to 54 MB, P90 from 94 MB to 79 MB, P99 from 113 MB to 97 MB, and P999 from 133 MB to 118 MB. That final figure created about 10 MB of headroom below the limit.

Worker memory usage after profiling fixes

What administrators should check

  • Choose a deployed Worker version receiving representative traffic; an idle Worker may not yield a useful production profile.
  • Set a bounded duration, such as 5,000 ms for an initial CLI test, then capture again when the fault is observable.
  • Inspect the widest flamegraph frames and the table sorted by samples; verify a suspected issue in code before changing it.
  • For memory incidents, compare allocation owners with feature flags and instrumentation that may be only partially disabled.
  • Enable source maps for TypeScript, retain downloaded profiles with the incident record, deploy a focused change, then compare percentiles and error counts.
  • For Durable Objects, target the named object when the issue belongs to a stateful actor rather than treating all Workers as equivalent.

Operational limits

Cloudflare’s runtime samples without holding the isolate lock for the full capture. It acquires the lock to start the V8 CPU profiler, releases it while normal requests execute, then reacquires it to stop profiling and serializes results outside the critical section. This avoids stopping JavaScript execution during measurement. Durable Objects require more routing work because they are stateful and can move, but the platform can route a request to the live primary actor for a named object.

The feature is not continuous profiling. Operators must explicitly start a session, so a rare incident can be missed; memory profiling also sees allocations made during the capture window, not allocations that happened at startup. Cloudflare says continuous profiling is under development. Until then, on-demand captures are most useful when tied to an alert, a reproducible traffic period, and a before/after validation plan.

Conclusion

On-demand profiles give Workers administrators a direct production view of CPU hot paths and memory allocation. The R2 and Prometheus examples show why that matters: both fixes depended on evidence that metrics alone did not reveal. Use short, targeted captures, preserve source maps, and measure the result after each change.

Source: Cloudflare — Introducing on-demand CPU and memory profiling with flamegraphs for Workers and Durable Objects.