Cloudflare made Python Workers generally available on September 21, two years after the first preview. The announcement, written by Gyeongjae Choi, Dominik Picheta and Hood Chatham, says Python is now a first-class language on the Workers platform, next to JavaScript and TypeScript. Two of those three authors are Pyodide core maintainers, which tells you how Cloudflare got here.
The runtime hasn't changed shape. Python still runs as CPython compiled to WebAssembly, through Pyodide, inside a V8 isolate in workerd. What changed is the amount of glue you have to write, the size of the bundle you can ship, and how many packages you can expect to load.
What shipped in the three weeks before GA
Cloudflare assembled the release piece by piece through September. The changelog shows the sequence.
- September 2: ASGI and WSGI connectors, so FastAPI, Django and Flask run without a server process.
- September 4: the bundle limit moved from 3 MB compressed on free plans and 10 MB on paid plans to 64 MiB uncompressed on both.
- September 8: Python 3.14 became the default for new Workers through the compatibility date. Versions 3.12 through 3.14 are selectable with flags.
- September 16: Hyperdrive support, which means PostgreSQL and MySQL drivers work.
The bindings change is the one Python developers will feel first. Before GA, sending a dict to a Queue meant importing to_js from pyodide.ffi and passing a dict_converter. Cloudflare says that pattern was a common source of bugs for both people and coding agents, so it moved the conversion into the runtime and the SDK. You now call env.QUEUE.send with a plain dict.
The Hyperdrive work is the heavier engineering. WebAssembly sandboxes stub out POSIX networking syscalls, so socket.connect fails, and every database driver built on the socket module fails with it. Cloudflare implemented the socket syscalls on top of the Workers connect API. The driver opens a TCP connection, the call gets translated into JavaScript at the syscall layer, and aiomysql or asyncpg never learn they are running inside a browser engine. The same trick, plus upstream patches that route httpx and requests through fetch, is what makes the openai, langchain and mcp packages load.
The limits are the same limits
GA is a support label, and it changes nothing about the box your code runs in. The Workers limits page is the document to read before you port anything.
- 128 MB of memory per isolate, counting the JavaScript heap and WebAssembly allocations together.
- 10 ms of CPU time per request on the free plan. 30 seconds by default on paid, configurable up to 5 minutes.
- 64 MiB uncompressed bundle, which now has to hold your vendored packages too.
- A filesystem that lives in memory and disappears with the isolate.
The threading and multiprocessing modules import fine and do nothing useful. There is one WebAssembly thread. venv doesn't exist. If your Django app shells out to ImageMagick or runs a Celery worker, none of that comes along.
Cold starts are the number Cloudflare still doesn't lead with.
Its own December 2025 post measured 1.027 seconds to cold start a Worker importing httpx, fastapi and pydantic, against 2.502 seconds for Lambda without SnapStart and 3.069 seconds for Cloud Run. That number comes from memory snapshots. At deploy time Cloudflare runs the imports at the top of your module, captures the WebAssembly linear memory, and restores it on the first request. Without the snapshot, the same imports took about 10 seconds. In the Hacker News thread on the GA post, one commenter cited a Wasmer Edge benchmark at around 60 ms for a minimal app versus around 900 ms on Workers, and another said Lambda is faster and more consistent. Dominik Picheta from Cloudflare answered that request sharding has cut how often cold starts happen and that "there is still more to do here." Nobody produced a cold start figure with native packages loaded.
Simon Willison's writeup describes what local development looks like. pywrangler, published to PyPI as workers-py, runs your code with Pyodide, in WebAssembly, in V8, inside a 123 MB workerd binary. It needs uv and Node.js installed. You are running a Python that a JavaScript engine hosts, with everything that implies.
PEP 783 is the part that outlives the product
The durable contribution here has nothing to do with Cloudflare's network. Any Python package with a C, C++ or Rust extension has to be cross-compiled for WebAssembly, and until this year there was no standard way to publish such a build. The Pyodide maintainers built and hosted more than 300 packages themselves. That was the bottleneck.
Hood Chatham authored PEP 783, which defines a pyemscripten platform tag for wheels. The PEP was accepted this spring. PyPI now accepts wheels tagged pyemscripten_2025_0 for Python 3.13 and pyemscripten_2026_0 for Python 3.14, and cibuildwheel and maturin both know how to produce them. Pydantic has already published one. A maintainer who adds a pyemscripten target to CI gets a package that works in Pyodide in the browser and on Cloudflare, and Cloudflare didn't have to build or host it.
The cost of that lands on maintainers, and one of them said so. A urllib3 maintainer wrote in the Hacker News thread that Cloudflare funded the work to add the WebAssembly backend, and urllib3 now owns that backend. They cited CVE-2025-50182, where browser fetch semantics didn't match what urllib3 promised about redirects, as the kind of bug that comes with it. That's a fair complaint. A vendor underwrites a feature, ships a press release, and the maintainers carry the security response for the next decade. Cloudflare's docs tell users who hit an unsupported package to ask the maintainer for a pyemscripten wheel, which pushes the same cost further out.
Where I'd put this, and where I wouldn't
The fit is narrow and useful. A FastAPI service that validates input, calls a model, writes to R2 or D1, and returns JSON is the shape Workers likes. The 128 MB ceiling is fine for that. A cold start of about a second matters less when sharding keeps warm isolates around and the request itself spends 800 ms waiting on an LLM. MCP servers in Python, webhook handlers, queue consumers, small agents. Cloudflare's examples repo is all of this, and it's the right list.
I would not move a Django monolith. Django runs, per the announcement, through the WSGI connector. But a Django app that has lived on a VM for years leans on a local disk, on background threads, on a process manager, and on pip installing whatever the requirements file says. Each of those is either absent or a project on Workers. The framework ports. The app around it doesn't.
Ops reads this differently from a developer. If a team asks me to host Python at the edge, my first question is whether they've checked their dependency list against PyPI for pyemscripten wheels. The second is what happens at 128 MB, because Python's memory habits do not shrink in WebAssembly. The third is whether anyone measured the cold start with their real imports, since Cloudflare's published number covers three packages and nobody on the thread got a number for numpy or pandas. The fourth is who gets paged when a request hits the CPU limit and the isolate dies in the middle of a transaction.
Cloudflare's post ends by saying GA is the start and that memory efficiency and performance are next. I take that at face value, and I read it as a statement about what isn't done. My prediction: the pyemscripten tag ends up mattering more than Python Workers does. Within two years, most large scientific and web packages on PyPI will ship one, and the winners will be browser notebooks and every serverless vendor that adopts Pyodide, with Cloudflare one of several.