Deploy FastAPI on Cloudflare Workers: the packages pip won't install
Deploy FastAPI on Cloudflare Workers now that Python is GA: what pip installs cleanly, what needs a Wasm build, and the C-extension wall in between.

TL;DR: Cloudflare’s Python Workers went generally available on September 21, 2026, and you can now deploy FastAPI on Cloudflare Workers with the same ASGI app you already run, no JavaScript glue code required for bindings. Django, Flask, and socket-based drivers like aiomysql and asyncpg work today too — but any package with a native C, C++, or Rust extension (numpy, pandas, cryptography) still needs a Wasm-targeted wheel built with cibuildwheel before Pyodide will import it.
That’s the whole story compressed into two sentences, and it’s also the part every announcement post skips. This is the deploy guide: what actually runs today, what the GA release changed under the hood, and exactly which packages will fail your build — and why.
What Is a Python Worker on Cloudflare?
A Python Worker is a Cloudflare Worker whose runtime interprets Python instead of JavaScript, using Pyodide — a WebAssembly build of CPython that Cloudflare runs inside the same V8 isolate that received the HTTP request. There’s no separate Python process, no container, and no cold database pool to boot: the interpreter loads inside the isolate the way a JavaScript bundle would, and your app code (WSGI or ASGI) runs from there.
That single architectural fact is why the deploy story looks nothing like a traditional Python host: you’re not choosing a WSGI server, a process manager, or a container base image. You’re compiling your app into the same edge-function model Cloudflare already runs for JavaScript, with a different interpreter inside it.
Why Python Workers Reaching GA Actually Matters
Cloudflare shipped the Python Workers beta about two years before this GA announcement, and the gap between beta and GA is the actual news, even though “generally available” is the headline everyone else ran with. Two things changed:
- The JavaScript interop glue is gone. Sending a plain dict to a binding used to require
to_js(payload, dict_converter=js.Object.fromEntries)— a line of JS-interop boilerplate wedged into every Python handler that touched a Queue, a Durable Object, or Workers AI. GA accepts the dict directly. - Raw TCP sockets showed up. The beta had no path to a live socket, so any driver or HTTP client that opens one at a low level simply didn’t work. GA adds that support, which is the specific thing that unblocks
aiomysqlandasyncpgover a Hyperdrive binding.
Neither change touches performance or pricing — Cloudflare’s post doesn’t publish a single cold-start number, a memory ceiling, or a request-cost figure, and you should be suspicious of anyone who quotes one as fact. What did change is friction: code that used to need a JavaScript-shaped workaround now reads like ordinary Python.
There’s also a quieter reason this matters if you’re doing anything AI-shaped: Cloudflare explicitly supports openai, langchain, and mcp inside a Python Worker, plus a langchain-cloudflare integration for wiring straight into Workers AI and Vectorize. If your stack already leans on LLM engineering patterns built in Python — chains, tool-calling agents, retrieval pipelines — you can now run that orchestration layer at the edge instead of proxying it through a separate origin.
How Do You Deploy FastAPI on Cloudflare Workers?
The deployment mechanics don’t change from what Cloudflare has supported since the beta — GA doesn’t add new config surface, it removes friction from the surface that was already there.
Deploying FastAPI in five steps
- Point
wrangler.tomlat Python. Setmain = "src/app.py"and addcompatibility_flags = ["python_workers"]— that’s the flag that tells Wrangler this entry point is Python, not JavaScript. - Write the ASGI adapter, not a new app. Your existing
FastAPI()instance is the same object you’d run anywhere; the Worker’son_fetchhandler bridges the WorkersRequest/Responseinto the ASGI calling convention FastAPI already expects. - List pure-Python dependencies in
requirements.txt. FastAPI, Starlette, and Pydantic all ship anone-anywheel, so they install exactly the way they would on any other host. - Bind Hyperdrive before you touch a database driver.
asyncpgandaiomysqlneed the raw-socket support GA added — route them through a Hyperdrive binding instead of a direct TCP connection string. - Run
wrangler deploy. The Worker ships to the same 300+ edge locations and the samerun_worker_firstrouting model as a JavaScript Worker, because nothing about the deployment topology changed — only the interpreter inside it did.
If you’ve already deployed an MCP server on Cloudflare Workers, step 1 will look familiar — it’s the same wrangler.toml-first mental model, just with a Python entry point instead of a TypeScript one. And if that Worker needs to sit behind something other than the open internet, gating it with Cloudflare Access works identically regardless of which language wrote the handler.
Which Packages Actually Work in Python Workers?
This is the part the GA announcement undersells: whether a package works has nothing to do with how popular it is and everything to do with how it was built.
| Package category | Examples | Works in a Python Worker today? |
|---|---|---|
| Pure-Python wheel | FastAPI, Django, Flask, langchain, mcp | Yes — unmodified |
| Socket-based driver | aiomysql, asyncpg (via Hyperdrive) | Yes — new in this GA release |
| C / C++ / Rust extension | numpy, pandas, cryptography | No — needs a cibuildwheel-built Wasm wheel first |
The dividing line is the wheel format, not the package name. A pure-Python package publishes a none-any wheel — the exact same bytes install on Linux, macOS, Windows, or Pyodide’s Wasm target, because there’s no compiled code inside it to target a platform. A package with a C, C++, or Rust extension publishes a separate compiled wheel per platform, and until this year almost none of them published one for Pyodide’s pyemscripten target.
What Breaks: C Extensions and the Wasm Wall
Here’s the failure mode you’ll actually hit: you pip install numpy (or it’s a transitive dependency of something you do want), and the install step can’t find a matching wheel for the Wasm platform Pyodide runs on. It isn’t a bug in your code — it’s that nobody has cross-compiled that exact version of that exact package to pyemscripten yet.
Two ways out, in order of how much work they are:
- Drop the dependency if you can. Most Workers don’t need
numpy-grade numerical code; if you’re doing light aggregation, plain Python or a pure-Python alternative is often enough, and it sidesteps the wall entirely. - Build it yourself with
cibuildwheel. Cloudflare’s post points atcibuildwheelas the tool that cross-compiles a C-extension package to a Wasm wheel. It’s real work — you’re building a package maintainer’s release pipeline for one dependency — but it’s the documented path, and PEP 783 exists specifically to standardize thepyemscriptenplatform tag so more maintainers ship one by default instead of every consumer building their own.
If your app leans on heavier ML inference rather than a general-purpose numerical library, don’t fight this wall at all — hand that workload to Workers AI instead of trying to shoehorn a model-serving stack’s C extensions into Pyodide.
Best Practices for Running Python Workers in Production
- Treat “it’s Python” as an interface, not a guarantee. Audit
requirements.txtfor C-extension packages before you commit to Workers, not after a deploy fails. - Route every database connection through Hyperdrive. It’s the supported path for the sockets GA unlocked, with connection pooling built in.
That covers dependencies and data access. The rest is about not over-trusting the “it’s just Python” framing:
- Test the real
wrangler deploypath, not just a localpip install. A wheel installing on your laptop says nothing about whether apyemscriptenwheel exists. - Reach for Workers Workflows for anything long-running. A Python Worker is still request/response under the hood; durable jobs belong in Cloudflare Workflows.
- Don’t assume performance parity with a JS Worker until you’ve measured it. Cloudflare hasn’t published comparative numbers, and Pyodide adds real interpretation overhead.
If your app also calls out to OpenAI’s SDK, the version pin matters as much as the platform does — see the httpx2 migration guide for the breaking change that trips up exactly this kind of Python service.
FAQ
Can I run FastAPI on Cloudflare Workers today? Yes. FastAPI ships as a pure-Python wheel and runs unmodified inside Pyodide. You write the same ASGI app you’d deploy anywhere else and point wrangler.toml at it — no rewrite required.
Does numpy or pandas work in a Python Worker? Not as a plain pip install. Both ship native C extensions, and Pyodide only runs packages built for its Wasm target. Someone has to cross-compile them with cibuildwheel into a pyemscripten wheel first.
What actually changed when Python Workers went GA? Bindings now accept plain Python dicts instead of the to_js() glue the beta needed, and Cloudflare added raw TCP socket support so aiomysql and asyncpg can reach a database over Hyperdrive.
Is a Python Worker slower than a JavaScript Worker? Cloudflare hasn’t published cold-start or latency numbers for this release. Pyodide adds an interpretation layer a JS Worker doesn’t have — benchmark your own workload rather than trusting an unsourced number.
Can I use LangChain or the OpenAI SDK in a Python Worker? Yes — Cloudflare explicitly lists openai, langchain, and mcp as supported, plus a langchain-cloudflare integration for Workers AI and Vectorize.
Do I need to rewrite my FastAPI app to deploy it on Workers? No — the app code keeps the same ASGI interface. You add a wrangler.toml entry point, and you need a plan for any C-extension dependency: drop it or get a Wasm build.
Sources
- Cloudflare Blog, “Python Workers are now generally available”, September 21, 2026.
- Pyodide documentation — the WebAssembly CPython distribution Python Workers runs on.
- PEP 783 — the proposed
pyemscriptenplatform tag for Pyodide-targeted binary wheels.
Frequently asked questions
Google Search · Preferred sources
Prefer this site on Google
If you already read this writing, add umesh-malik.com as a Preferred Source. Google can then highlight it with a preferred badge in Top Stories, AI Overviews, and AI Mode — for you, not as a site-wide ranking boost.
Related Articles

Web Engineering
FastAPI Finally Has Native SPA Support: app.frontend() Explained
FastAPI 0.138.0 ships app.frontend() — a native way to serve React, Vue, and Svelte SPA builds. How it works, real use cases, and what it still can't do.

Web Engineering
Migrate to a New CMS With Zero Downtime: a 28K RPS DDoS Mid-Rollout
Here is how to migrate to a new CMS with zero downtime: a cookie-routed proxy Worker, staged 1%-100% rollout, and a 28,000 RPS DDoS absorbed mid-migration.

Web Engineering
SVG to MP4 in the browser: a two-step workflow, no server
SVG to MP4 in the browser needs no server: paste a URL and 30MB of ffmpeg.wasm renders every frame in your tab. The one catch that trips people up.
Keep reading
Get new posts on AI, Claude Code & LLMs
New deep-dives on AI engineering, Claude Code, and developer tooling — follow along however you prefer.
About the Author
Software engineer writing about AI, Claude Code, LLMs, OpenAI, Anthropic, and developer tooling. 5+ years building production systems at Expedia Group, Tekion, and BYJU'S.