Skip to content

CPU Time Limits on Cloudflare Workers for AI Calls

9 min read · updated August 11, 2026

The most common worry about running model calls from a Worker is that a slow provider will blow through the CPU limit. It will not, and the reason is worth understanding precisely, because it also tells you what will.

Two clocks, and only one has a limit

A Worker invocation has a wall-clock duration and a CPU time. Wall clock is how long the request took from the outside. CPU time is how long the isolate spent actually executing your JavaScript.

Cloudflare’s limits page documents the duration of an HTTP request as having no limit while the client remains connected. The limit that exists is on CPU time. And crucially, the seconds your code spends suspended at an await on a fetch are not CPU time — the isolate is not running, the event loop has moved on, and nothing accrues.

So a Worker that sends a prompt to a model and waits ninety seconds for the answer has used a handful of milliseconds of CPU: parsing the incoming request, building the outgoing one, and parsing the response. The ninety seconds do not appear in the number that is capped. This is not a loophole; it is the design of a platform that packs many isolates onto one machine and charges for the resource that is actually scarce.

The same reasoning is why Cloudflare can offer this shape at all, and it has a direct analogue on the other platform in this cluster — Vercel’s Active CPU billing pauses during I/O for the same reason.

What actually counts as CPU time

If waiting is free, what is not? In an AI Worker, the CPU-consuming work is nearly always one of these:

  • Parsing large JSON. await response.json() on a long completion, or on an embedding response containing thousands of floats, is real work. A 3,000-dimension embedding batch of 100 items is a large array to materialise.
  • Parsing a stream, chunk by chunk. This is the one people miss. Streaming does not reduce total CPU — it spreads it. Every server-sent-event frame you split, decode and JSON.parse is CPU, and a long answer is hundreds of frames. If you are transforming the stream rather than passing it through, that cost is yours.
  • Base64 encoding and decoding. Images going to a vision model, audio going to transcription. Encoding a few megabytes of binary into base64 in JavaScript is not free.
  • Anything per-token in your own code. Client-side tokenisation to estimate cost, regex over the full completion, or splitting a document into chunks for embedding.
  • Cryptography. Hashing a request body for a cache key, verifying a webhook signature, computing an HMAC per request.

The pass-through case is the cheapest and it is worth arranging for. Returning the provider’s Response body directly — return new Response(upstream.body, upstream) — streams bytes without your isolate touching them, so a long answer costs you almost nothing regardless of its length.

The documented numbers

Cloudflare’s Workers limits page documents CPU time per HTTP request as 10 ms on the Free plan and up to 5 minutes on the Paid plan, with a default of 30 seconds. The configurable maximum is documented as 300,000 ms. Memory is documented as 128 MB per isolate on both plans. Subrequests are documented as 50 per request on Free and 10,000 on Paid.

Two of those interact with AI work more than the CPU figure does. The 128 MB memory cap is what you hit when you buffer a large model response or a batch of embeddings in memory rather than streaming it. And the Free plan’s 10 ms is genuinely tight for anything that parses a substantial response — it is enough to proxy, and not enough to post-process.

Cron triggers and queue consumers have their own figures: Cloudflare documents queue consumers and cron triggers as having a 15-minute duration limit, which is a wall-clock limit and therefore does apply to a handler that spends its time waiting.

Plan limits are exactly the kind of figure a vendor revises; these are the documented values at the time of writing. Cloudflare, Workers limits

Raising the limit, and when not to

The CPU limit is configurable in Wrangler through the limits key:

// wrangler.jsonc
{
  "limits": {
    "cpu_ms": 120000
  }
}

Before you raise it, be sure the number you are hitting is the one you think. Raising cpu_ms because a provider is slow does nothing, because provider slowness was never counted. If you are genuinely exceeding 30 seconds of CPU in one request, you are doing heavy computation on the edge — chunking a large document, or transforming a very long stream — and the better answer is usually to move it off the request path entirely into a queue consumer, where the work is retried on failure instead of failing a user request.

Raising the limit also raises what a runaway costs you. An accidental infinite loop under a 30-second cap wastes 30 seconds; under a five-minute cap it wastes ten times as much, per request, until you notice.

What it looks like when you exceed it

Cloudflare documents the CPU-exceeded case as returning Error 1102, “Worker exceeded resource limits”. In the dashboard it appears under Metrics as an invocation status of “Exceeded CPU Time Limits”, and in analytics the invocation outcome is exceededCpu.

The diagnostic signature is what distinguishes it from a provider problem: the failure correlates with response size rather than with provider latency, and it happens after the upstream call succeeded. If your errors cluster on long completions and large documents while short requests are fine, you are looking at CPU, not at the model. Enable Workers observability (observability.enabled in your Wrangler configuration) and check the outcome field rather than guessing — a 1102 and a provider timeout look identical from the client.