Platform Change · 12 min read

Cloudflare Workers 64 MiB: AI API Bundles

Cloudflare Workers size limit 2026: compressed 3 MB/10 MB caps removed for a 64 MiB uncompressed bound, plus D1 free-tier hard limits.

A Ceiling Removed and a Floor Added in the Same Week

Cloudflare's developer platform moved twice in the first week of September 2026, and the two changes point in opposite directions. On September 4 Cloudflare deleted the compressed Worker size limit — the 3 MB cap on the Free plan and the 10 MB cap on Paid — and replaced it with a single 64 MiB uncompressed bound that applies to every plan. On September 1, D1 stopped treating its free-tier row limits as advisory and started returning hard query errors when an account exceeds them.

For anyone running an AI API workload on Workers — a proxy in front of an OpenAI-compatible endpoint, a RAG service, an agent gateway, a streaming relay — this pair matters more than either headline suggests. The first change removes a packaging constraint that has quietly shaped how AI SDKs get bundled for the edge for the past two years. The second adds a runtime constraint that shows up as production errors rather than dashboard warnings. Read together, they are a trade: Cloudflare made it easier to ship a large Worker and harder to run a careless free database behind it.

This article works through both from the vendor's own documentation, then maps the specific bundle-size workarounds in AI API projects that are now unnecessary — and the D1 audit that replaces them as the thing you should actually be doing.

What Exactly Changed About Worker Size

The mechanic is worth stating precisely because the number 64 MiB is easy to misread. Wrangler has always bundled your code and compressed it before upload. What changed is which of those two measurements Cloudflare checks.

Previously, Cloudflare checked the compressed size and rejected deploys above 3 MB on the Free plan or 10 MB on Paid. That check is gone. Cloudflare now checks only the uncompressed bundle size, and the limit is 64 MiB across all plans.

That distinction changes the practical headroom dramatically, because compression ratios on JavaScript bundles are far from uniform. A bundle dominated by application logic typically gzips to roughly a fifth of its raw size — so the old 3 MB compressed Free ceiling was landing somewhere near 15 MB of real source. A bundle dominated by dense generated data tables, protobuf descriptors, or embedded JSON schemas compresses much better, and could previously approach 25-30 MB raw before tripping the 3 MB compressed gate.

PlanOld limit (compressed)New limit (uncompressed)What Cloudflare checks now
Workers Free3 MB64 MiBUncompressed bundle only
Workers Paid10 MB64 MiBUncompressed bundle only

The gzip figure is still printed by Wrangler, but it is now informational — it no longer gates the deploy. If you have ever trimmed a dependency solely because the gzip number in your build output crept past a threshold, that pressure is gone.

How to Check Your Bundle Before You Deploy

The dry-run flag is the cheapest way to see the number Cloudflare will actually enforce. It bundles and reports without uploading:

wrangler deploy --outdir bundled/ --dry-run

The output looks like this:

Total Upload: 259.61 KiB / gzip: 47.23 KiB

The Total Upload value is your uncompressed bundle size, and that is the number measured against the 64 MiB limit. The gzip value is shown for reference only. Two details matter if you are auditing an existing project: the value is binary (a MiB is 2^20 bytes, not 10^6), and it counts the entire bundle including every dependency Wrangler inlined — not just your own source files.

One caveat about interpreting that number: 64 MiB is the ceiling on what you can upload, and it is a separate limit from Worker startup time, which is capped at 1 second on both plans. A bundle that fits comfortably under 64 MiB can still fail to deploy if its top-level initialisation work pushes past that one-second budget. Size and startup cost are different constraints, and relaxing one does not relax the other.

The AI-Specific Bundling Workarounds You Can Now Delete

This is the part that matters most for an AI API project, because edge-deployed AI services have an unusually dependency-heavy bundle profile. Three workarounds in particular became common specifically because of the old compressed ceiling.

1. R2-Hosted Model Metadata and Schema Splitting

The most common pattern was moving large static payloads out of the bundle into R2 (or KV) and fetching them at runtime. The usual candidates were OpenAPI specifications for the upstream API you were proxying, provider model catalogues (name, context window, pricing, capability flags for hundreds of models), and tokeniser vocabularies. Each of these is large, changes on a slower cadence than your code, and compresses unevenly — exactly the profile that made the compressed gate painful.

If your Worker was fetching a 2 MB model catalogue from R2 on every cold start just to stay under the upload limit, that fetch is now an avoidable cold-start cost. Inlining the catalogue is a legitimate option again — but measure before you move it, because the runtime latency you saved by not fetching may be worth less than the startup time you add. The 64 MiB budget is permission to inline, not an argument for it.

2. Splitting One Logical Service Across Multiple Workers

The second pattern was architectural: a service that logically should have been one Worker got split into several, with service bindings wiring them back together, purely to keep any single bundle under the compressed threshold. A typical AI gateway would end up as a routing Worker, a provider-adapter Worker, and a separate Worker for the request/response transform layer — not because the boundaries were meaningful, but because the size gate forced a cut somewhere.

Collapsing those back into one Worker is now possible, and it has real benefits: fewer network hops between your own components, simpler deployment, and one place to reason about request context. But the split may have acquired genuine value along the way — separate CPU budgets, independent deploys, isolated blast radius. Treat consolidation as a refactor to evaluate, not a cleanup to perform reflexively.

3. Vendoring Reduced Copies of SDKs

The third pattern was the most maintenance-heavy: keeping a locally patched, tree-shaken fork of an AI SDK so that only the endpoints you called were bundled. Teams did this because the official client often ships broad surface area — every model's request builder, every streaming variant, every tool-calling helper — and the compressed gate made the full package expensive.

Vendored forks are the workaround most worth revisiting, because they carry ongoing cost: every upstream release becomes a manual merge, and security fixes have to be tracked by hand. If your fork existed only for size, the official package is worth re-testing. If it existed for a functional reason — a missing endpoint, a proxy quirk, a custom retry policy — the size limit was never the real motivation and the fork should stay.

What Did Not Change

The size increase does not loosen the constraints that actually bite AI workloads at runtime. These are unchanged on both plans and are the ones that determine whether a large Worker is usable once it is deployed:

ConstraintWorkers FreeWorkers PaidWhy it matters for AI APIs
Memory128 MB128 MBStreaming buffers and in-memory tokenisers still have a hard ceiling
CPU time per request10 ms5 minThe Free plan cannot do meaningful local inference or heavy transforms
Subrequests per request5010,000Multi-provider fan-out and agent tool loops are capped on Free
Simultaneous open connections66Parallel upstream calls are limited identically on both plans
Startup time1 second1 secondLarge bundles still pay for top-level initialisation
Requests100,000/dayNo limitFree plan throttles before your AI spend does

Note the shape of this table. Every constraint that governs what runs inside the Worker is either identical across plans or dramatically worse on Free. The 64 MiB limit is the one dimension where Free and Paid are now equal — which means a large bundle on the Free plan can be uploaded successfully and still fail in production on CPU time or memory. Upload capacity is not run capacity.

The Other Half: D1's Free Tier Got Teeth

The second September change is the one more likely to page you. Effective September 1, 2026, D1 queries on the Workers Free plan fail and return errors when an account exceeds the daily row read or row write limits. Previously these were soft limits — you got a warning and the queries kept working. Now the Worker Binding API and the REST API both return errors until the limit resets at midnight UTC. Stored data is not affected; only the ability to query it is.

The thresholds that now hard-fail:

MetricWorkers FreeWorkers Paid
Rows read5 million / dayFirst 25 billion / month included, then $0.001 / million rows
Rows written100,000 / dayFirst 50 million / month included, then $1.00 / million rows
Storage5 GB totalFirst 5 GB included, then $0.75 / GB-month

Two errors identify the condition, and both are specific enough to route on:

Your account has exceeded D1's free tier daily row read limit.
Upgrade to a paid plan or wait until tomorrow (midnight UTC) to continue.
Your account has exceeded D1's free tier daily row write limit.
Upgrade to a paid plan or wait until tomorrow (midnight UTC) to continue.

Cloudflare sends email alerts when the daily limit is reached, so the first signal is a notification rather than a support ticket — but only if someone is reading that inbox.

The Asymmetry That Catches Teams Out

Look at the read and write limits together and the failure mode becomes obvious. You get 5,000,000 row reads per day but only 100,000 row writes — a 50:1 ratio. Read-heavy agent workloads are therefore far more likely to be fine than write-heavy ones, and a workload that writes frequently is the one to audit first.

The trap is what a single mis-indexed query costs. A full table scan on a million-row table reads a million rows, so from a five-million-row budget that is five requests before the free tier is exhausted for the rest of the day. Row reads are counted per row examined, not per row returned — which means a query that returns three rows after scanning a million has still spent a million rows of budget. The cost is in the scan, not the result.

This is why the failure tends to arrive without warning in development and immediately in production. A table holding a few thousand rows during testing produces scans that are invisible against a five-million budget. The same query against a table that grew to a few hundred thousand rows costs a hundred times more per call, and the first symptom is not a slow query — it is the error string above.

The Audit That Replaces the Workarounds

If the bundle workarounds described above were your main size-management strategy, the D1 enforcement is the work that should now occupy that attention. Cloudflare's own guidance is to inspect query activity and add indexes to reduce row reads. The practical version of that, in order:

  • Find the table scans first. Any query without a supporting index on its filter or join columns is a candidate for a full scan, and full scans are what consume row-read budget superlinearly as tables grow.
  • Watch the meta object and the dashboard. D1 exposes row metrics through the Worker API's meta object, the GraphQL Analytics API, and the dashboard's Metrics → Row Metrics view. Measure before and after any index change rather than assuming it helped.
  • Count writes separately from reads. The 100,000/day write budget is the tighter constraint. A logging table that writes one row per request, across 100,000 free-tier requests, consumes the entire daily write allowance on bookkeeping alone.
  • Move writes off the request path where you can. Batching writes, or sending them to a queue that flushes, converts a per-request write cost into a per-batch one — usually the single largest reduction available to a free-tier workload.
  • Price the upgrade against the value of the workload. A Workers Paid plan starts at $5 per account per month and removes the daily D1 limits entirely, replacing them with monthly included allowances. For a service that is already failing in production, that is frequently cheaper than the engineering time spent optimising around the cap.

There is a second-order effect worth naming. Because the limits reset at midnight UTC, a workload that exhausts its budget has a fixed outage window rather than a degraded one. If your service is consumer-facing across time zones, midnight UTC lands squarely in the middle of the European working day — so the failure is exposed to users at exactly the moment your domestic traffic is lowest and your ability to respond is slowest. Design the alerting accordingly, and prefer alerting on rate of consumption rather than on the error, because the error arrives after the budget is already gone.

What to Do This Week

The honest summary is that the two changes are not symmetric in urgency. The 64 MiB limit removes a constraint and requires nothing of you — no migration, no flag, no deadline. It is an opportunity to simplify, and the right response is to identify which of your size-driven workarounds existed only for size, then revisit those selectively. Most teams should not rush this; a vendored SDK fork that works is not improved by an unforced refactor.

The D1 change is the opposite. It took effect on September 1, it converts warnings into errors, and its failure mode scales nonlinearly with table growth — which is the classic shape of a production incident that appears once and then never stops. If you run a free-tier D1 database behind an AI API workload, the useful action is to check today's row-read and row-write consumption against the 5,000,000 and 100,000 daily budgets, and to identify any query that performs a full table scan.

The connection between the two is the useful takeaway. Cloudflare relaxed what you can put into a Worker and tightened what you can cheaply do at runtime. Building a larger edge-native AI service is easier than it was last month; running one for free is harder. Plan against the second fact, and treat the first as latitude you can choose to use.

Sources

  • Cloudflare changelog, "Deploy larger Workers — up to 64 MiB for both free and paid plans", September 4, 2026
  • Cloudflare changelog, "D1 enforces free tier daily query limits", September 1, 2026
  • Cloudflare Workers platform limits documentation (Worker size, startup time, account plan limits)
  • Cloudflare D1 pricing documentation (billing metrics, free-tier read/write budgets)

Deploying an AI API on Cloudflare Workers?

Worker size is now 64 MiB uncompressed on every plan, but D1 free-tier row limits hard-fail at 5M reads and 100K writes per day. Check both before you ship.

Workers Platform Limits →