FR
live

Cloudflare adds on-demand CPU and memory profiling for Workers and Durable Objects

On October 9, 2026, Cloudflare made on-demand CPU and memory profiling generally available for Workers and Durable Objects, with interactive flamegraphs generated directly in production. Use it to chase memory leaks and hot functions instead of guessing from logs and aggregate metrics.

A row of stacked translucent acrylic blocks of varying widths forming a bar-chart silhouette, lit from below.

October 9, 2026. Cloudflare announces CPU and memory profiling for Workers and Durable Objects. 128 MB. That is the per-Worker memory limit, which one internal example pushed to 133 MB at P999. 2.7×. That is the speedup the R2 team got after removing a redundant tree traversal spotted in a flamegraph. Why it matters: logs and aggregate metrics do not tell you which function is burning your cycles or allocating your memory — production profiling does.

Why profile in production instead of locally

Figuring out why an application uses more CPU or memory than expected is one of the most frustrating problems in serverless. Logs tell you what happened, not where the time went. Aggregate metrics give you a trend, not a cause. Profiling delivers the precise answer: it shows the exact function where your code is consuming CPU or allocating memory.

Cloudflare already supported local profiling through Chrome DevTools, but never on Workers running in production. Profiling locally has a structural limit: a local Worker receives neither the same kinds nor the same volume of requests as one in production. The best way to understand an application is to profile it where it actually runs.

The new capability is on-demand profiling of active Workers. From a Worker’s Observability page, you can request a CPU or memory profile, inspect it as an interactive flamegraph, then download the profile file for deeper analysis.

How to start a profile

Two paths lead to a profile. From the command line, using the cf tool:

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

Or from the dashboard: Build → Compute → Workers & Pages, select your Worker, open the Observability tab, and choose “Flamegraph.” You then pick the duration of the profile and the version of the Worker to profile. Note that the Worker must receive enough traffic to be profiled — choose a version that is actually deployed.

In a flamegraph, each rectangle represents a function call, and its width represents the share of CPU time or memory used by that function. Click a function to zoom in, hover to see details. The table view complements the flamegraph by sorting functions by sample count. If your Worker is in TypeScript, enable source maps — otherwise your profile will show obfuscated, unreadable function names.

The downloaded file is a pprof profile, the open format popularized by Google. You can reopen it with the local pprof tool or in any compatible viewer such as Grafana Pyroscope, cross-referencing a Cloudflare flamegraph with your existing dashboards. That is what separates this profiling from a visual gimmick: it slots into an observability chain instead of staying locked inside the vendor’s console.

A 2.7× win from a single read

The most telling example comes from the R2 team, which profiled the Worker implementing the R2 binding. A 50-second CPU profile surfaced two hot spots. The first: a replacer function (genericR2JsonReplacer) that called itself recursively. Invoked by JSON.stringify on every node of the JSON tree, it was also walking the tree itself — a value nested five levels deep was processed five times. The fix made the function 2.7× faster.

The second hot spot was subtler: a duplicated call to a metrics function, heavy enough to represent 1% of CPU time on its own. Storing the result of the first call in a variable instead of calling it again freed a meaningful chunk of time.

The memory case is just as instructive. An internal Worker saw its P999 memory hover around 133 MB against the 128 MB limit, causing frequent evictions with an “Exceeded Memory” error. A heap profile opened with pprof showed that Prometheus code, supposedly disabled, accounted for 66.7% of allocations. It was instrumenting a large part of the Worker’s code paths, consuming memory even though the collected data never left the Worker. Removing the code path entirely brought the P999 back to about 10 MB under the limit.

For an SRE, this changes the debugging workflow. Instead of reproducing a memory leak locally — often impossible when the leak depends on production traffic — you capture a heap profile on the live isolate and read the allocation stack directly. Instead of staring at a CPU graph that only says “the Worker is slow,” you open the flamegraph and see which function is wide. The Cloudflare examples are instructive because they were found in code nobody suspected: a replacer function walking a tree it was already inside, and supposedly-disabled Prometheus instrumentation that was still allocating.

The mechanics under the hood

Profiling a Worker in production poses a problem local profiling ignores. Workers are replicated across multiple data centers and physical machines; a busy Worker can be replicated several times on a single machine. Durable Objects add another layer of indirection: they are dynamically movable. Before starting a profile, you therefore have to answer several questions — which version to profile, in which data center that version ran recently, whether the isolate belongs to the requesting account, and, for a Durable Object, where the live primary actor currently is.

The key constraint is to avoid stopping the Worker during collection. A profile is useful only if the application keeps executing. The runtime therefore holds the isolate lock only for the profiler’s lifecycle operations: it acquires the lock, starts a V8 profiler sampling at 1 ms, releases the lock for the collection window, then reacquires it to stop profiling and serialize the result outside the critical section. Holding the lock for the whole duration would block JavaScript execution and make the profile useless.

Durable Objects get a benefit of their own: being stateful and named, you can profile a specific object anywhere in the world. The runtime routes the profiling request to the machine that owns the actor and returns the profile of the exact isolate.

What it doesn’t do yet

On-demand profiling has two acknowledged limits. First, you must explicitly start the session — you can miss the window in which the Worker is misbehaving. Second, the memory profiler only sees allocations during the profiling window — a Worker that allocates heavily at startup will not show up.

Cloudflare says it is already working on continuous profiling: capturing samples automatically so you can simply explore profiles in the dashboard, and catching the rare events a manual capture misses.

Continuous profiling matters more than it sounds, because the most expensive incidents — the intermittent OOM at peak traffic, the latency spike tied to a specific payload shape — are precisely the ones a manual capture misses. Automated, always-on sampling turns those rare events from unreproducible anecdotes into searchable profiles.

Verdict

If you operate Workers or Durable Objects that approach the 128 MB limit or whose latency is drifting, turn profiling on today: a single 50-second profile was enough for the R2 team’s 2.7× win, and the internal memory case found its cause in one read. If your Workers are in TypeScript, start by enabling source maps, or your flamegraphs will stay unreadable. If you are not on Cloudflare, take the method rather than the tool: profiling in production — not locally — is the only way to see your real hot spots, and the wins come in multiplicative factors, not micro-optimizations.

References

The cyber brief, every Tuesday

The flaws that matter and the patches to apply, in a ten-minute read.

No spam. One-click unsubscribe.
read next

On the same topic

Amazon ECS Gateway automates service ingress and removes per-service provisioning

On October 20, 2026, AWS launched ECS Gateway, an account-level resource that provisions and manages Application Load Balancers, ACM certificates, WAF rules and security groups for your ECS services. A platform team defines the standard once, an application team connects a service with one line: the per-service ingress bottleneck is gone.

AWS puts S3 inside the Vercel Marketplace and swaps static keys for OIDC federation

On October 14, 2026, AWS made S3 — including S3 Tables and S3 Vectors — provisionable from the Vercel dashboard and v0, using an OIDC token exchange that removes static access keys from the path. For front-end teams that consume object storage without ever opening the AWS console, the days of an IAM key pasted into an .env file are over.

← Back to the feed

Type at least two characters.

↑ ↓ navigate ↵ open esc dismiss