# Python Workers GA: port FastAPI or Hyperdrive without to_js glue

> Python is first-class on Cloudflare Workers. Pick FastAPI, Hyperdrive, or LangChain+Workers AI first — and commit the Wrangler bindings in-repo.
> By Dave · 2026-09-22
> Source: https://otf-kit.dev/blog/python-workers-ga-fastapi-agents

Cloudflare made Python Workers generally available on September 21, 2026. GA here means Python is a first-class, fully supported language on the Cloudflare Developer Platform — not a side experiment. You bring Python code, libraries, and design patterns you already know, and connect them to Workers AI, R2, D1, Hyperdrive, Durable Objects, Queues, Workflows, and the rest of the platform. You can run FastAPI, Django, and Flask inside Python Workers. You can also create a Python Worker inside another Worker using Dynamic Workers.

The buyer question for an owned repo is narrower than the launch list. First promote FastAPI, Hyperdrive, or LangChain plus Workers AI — and which bindings land in Wrangler in that same PR. Do not spray every binding into config on day one. Pick the surface that unblocks the workload you already own, commit that binding, and prove the Pythonic path before you widen the graph.

![Python Workers GA — FastAPI Hyperdrive bindings](https://cdn.otf-kit.dev/blog/python-workers-ga-fastapi-agents/hero-20260922a.png)

## What GA changes for bindings

Before GA polish, Cloudflare bindings in Python Workers often needed explicit conversion at the RPC boundary. Sending a Python dictionary into a Queue meant glue like `to_js` with a `dict_converter` so JavaScript received an object. That forced Python developers to keep the JavaScript environment in mind while writing Workers, and it was a common source of error for humans and AI agents.

The runtime and Python SDK now encapsulate that type conversion. The same send is Pythonic:

```python
self.env.QUEUE.send({"key": "value"})
```

That line is the migration gate. If your Worker still imports `pyodide.ffi.to_js` only to push dicts into Queue, R2, or similar bindings, delete that glue in the same change that bumps you onto GA-shaped bindings. Keep Wrangler (or your config equivalent) as the source of truth for which bindings exist — the code should read `self.env.<BINDING>` without a JS translation layer.

## Port FastAPI without standing up uvicorn

If your owned API is already FastAPI (or another ASGI app), the Workers path is a thin connector, not a rewrite of handlers. In a native process you would run `uvicorn main:app`. In Python Workers, Cloudflare’s `workers.asgi` package bridges the same app:

```python
from workers import asgi

class Default(WorkerEntrypoint):
    async def fetch(self, request):
        return await asgi.fetch(app, request, self.env)

# or equivalently
Default = asgi.entrypoint(app)
```

Synchronous frameworks such as Django use `workers.wsgi` the same way: `Default = wsgi.entrypoint(app)`.

Under the hood, WSGI and ASGI are the contracts that keep framework code server-agnostic. On Workers, the platform itself is the web server. Global load balancing and scaling already live in the network, so you do not run uvicorn or Gunicorn inside the Worker. The connectors translate the incoming native request into ASGI or WSGI structures and pipe the response back with minimal overhead. Any Python web framework that speaks WSGI or ASGI can use the same bridge — not only FastAPI, Django, or Flask.

For a repo that already ships FastAPI routes, first promote means: add the ASGI entrypoint, wire `env` from `request.scope["env"]` (or the entrypoint helper) where handlers need bindings, and declare only the bindings those handlers call. A minimal Workers AI call from FastAPI looks like reading `env` from the request scope and awaiting `env.AI.run(...)` — the launch post shows that pattern with `@cf/openai/gpt-oss-120b`. Treat that as proof that framework code and platform bindings share one process, not as a requirement to call Workers AI on every route.

![ASGI bridge and Hyperdrive socket on Workers](https://cdn.otf-kit.dev/blog/python-workers-ga-fastapi-agents/inbody1-20260922a.png)

## Hyperdrive when the blocker was TCP

Relational Python apps were stuck when Python Workers lacked TCP sockets. Drivers such as `aiomysql` and `asyncpg` rely on the standard library `socket` module. Inside WebAssembly, POSIX networking syscalls were stubs that failed. Cloudflare implemented those socket system calls using the Workers connect API, translating open and read operations into the JavaScript calls the Workers runtime already uses. Drivers do not need to know about that bridge.

That is what makes Hyperdrive usable from Python Workers. Connect the database in Hyperdrive, then declare the binding in Wrangler:

```json
"hyperdrive": [
  {
    "binding": "HYPERDRIVE_MYSQL",
    "id": "<your-hyperdrive-id>"
  }
]
```

Connect with the driver you already know:

```python
hd = self.env.HYPERDRIVE_MYSQL
conn = await aiomysql.connect(
    host=hd.host,
    port=int(hd.port),
    user=hd.user,
    password=hd.password,
    db=hd.database,
    ssl=None,
)
```

If your owned service’s pain is Postgres or MySQL latency and connection churn at the edge, Hyperdrive is the first promote — not FastAPI cosmetics. Commit the Hyperdrive binding and a single read path before you port the whole ORM surface. Cloudflare documents which packages are supported for Hyperdrive in Python Workers; stay inside that list instead of assuming every wheel works.

## Wasm packages, PEP 783, and the agent stack

Packages with native C, C++, or Rust extensions must be cross-compiled to WebAssembly to run in Python Workers. Historically there was no standard way to do that for arbitrary packages, so Cloudflare compiled and hosted a limited set. That limited what you could import.

Cloudflare proposed PEP 783, which standardizes a platform called PyEmscripten for Python in browser-class runtimes. After more than a year of discussion, the proposal was accepted so maintainers can build and publish for PyEmscripten across environments that implement it. The Pyodide build toolchain was stabilized for package maintainers, and PyEmscripten support was added to `cibuildwheel`. Adoption is still in progress; if a package is missing, the launch post points to Discord or GitHub rather than promising every wheel today.

Separately, AI libraries such as `openai`, `langchain`, and `mcp` historically leaned on HTTP clients (`requests`, `httpx`) that broke when low-level sockets were missing. Upstream work routes those clients through the JavaScript `fetch` API in Wasm environments. Combined with the socket bridge above, the networking stack works inside Python Workers. You can run those libraries natively and combine them with Workers AI or proxy through Cloudflare AI Gateway.

LangChain on Workers AI via `langchain-cloudflare` looks like this shape:

```python
llm = ChatCloudflareWorkersAI(
    model_name="@cf/meta/llama-3.3-70b-instruct-fp8-fast",
    binding=self.env.AI,
    max_tokens=64,
)
chain = prompt | llm | StrOutputParser()
result = await chain.ainvoke({"profession": "electrician"})
```

If your owned agent already speaks LangChain, first promote is the `AI` binding plus a pinned model name in config — not a Queue graph. Keep the model string and binding name in-repo so agents and humans do not invent a different Workers AI id at deploy time.

![First-promote fork: FastAPI, Hyperdrive, or Workers AI](https://cdn.otf-kit.dev/blog/python-workers-ga-fastapi-agents/inbody2-20260922a.png)

## Patterns worth copying after the first promote

Cloudflare’s `python-workers-examples` collection shows production-shaped combinations once the first binding works.

One pattern is asynchronous AI orchestration: accept a user request, drop it on a Queue, use Workflows to orchestrate image generation through Workers AI, and store the result in R2 — all in Python Workers. That graph needs Queue, Workflows, Workers AI, and R2 bindings declared together. Promote it only after a single-path FastAPI or Hyperdrive or LangChain slice is green; otherwise you debug four bindings at once.

Another pattern is real-time stream processing with Bluesky Jetstream: a Python Worker holds an ATProto/Bluesky Jetstream WebSocket, backed by a Durable Object so long-lived state keeps the connection alive. That promote is Durable Objects first, not Hyperdrive.

Dynamic Workers matter when one Worker must create another Python Worker at runtime. Treat that as a later promote: get the child entrypoint and its bindings correct in isolation before you generate Workers from Workers.

## Which binding lands in-repo first

Answer the buyer question with the workload you already own:

1. **FastAPI / ASGI first** when you have an existing ASGI or WSGI app and need global fetch handlers without running uvicorn. Bindings: only what those routes call (often `AI`, later Queue or R2). Commit `workers.asgi` (or `workers.wsgi`) entrypoint plus Wrangler bindings in one PR.
2. **Hyperdrive first** when relational drivers were blocked on TCP. Binding: `HYPERDRIVE_*` with host, port, user, password, database from the binding object. Prove one `aiomysql` (or supported) query path before porting migrations.
3. **LangChain + Workers AI first** when the product is already an agent or chain. Binding: `AI`, with `ChatCloudflareWorkersAI` (or equivalent) and a model name pinned beside the Worker. Add Queue, Workflows, and R2 only when you adopt the async image pipeline pattern.

In every case, drop remaining `to_js` glue for dict payloads, keep binding names identical between Wrangler and `env`, and avoid declaring unused bindings “for later.” Unused bindings widen the blast radius for agents editing config. For timeout and retry discipline on outbound AI calls from owned backends, the same ownership habits in [API timeouts and retries for owned AI backends](https://otf-kit.dev/blog/api-timeouts-retries-ai-backends) still apply once `openai` or LangChain is talking through fetch.

Keep structured correlation like [structured production logs agents can triage](https://otf-kit.dev/blog/production-structured-logging-for-agents).

## Builder checklist

1. Confirm GA claims and code shapes on the primary Cloudflare post — Python first-class, Pythonic bindings, ASGI/WSGI connectors, Hyperdrive sockets, PEP 783 / cibuildwheel, LangChain Workers AI example.
2. Choose one first promote: FastAPI/ASGI, Hyperdrive, or LangChain+Workers AI.
3. Commit only the Wrangler bindings that promote needs; name them the same as `env` access in code.
4. Delete `to_js` glue for Queue (and similar) dict sends in the same change.
5. Only then add Queue+Workflows+Workers AI+R2, Jetstream+Durable Objects, or Dynamic Workers from the examples repo.

## Sources

- [Python Workers are now generally available](https://blog.cloudflare.com/python-workers-ga/) — Cloudflare Blog (September 21, 2026): GA meaning, Pythonic bindings, FastAPI/Django/Flask via `workers.asgi` / `workers.wsgi`, Hyperdrive and TCP via Workers connect API, PEP 783 PyEmscripten and cibuildwheel, `openai` / `langchain` / `mcp`, `ChatCloudflareWorkersAI`, Dynamic Workers, and example patterns (Queue+Workflows+Workers AI+R2; Bluesky Jetstream + Durable Objects).
