FastAPI on Cloudflare Python Workers: Production Guide

Published on 9/23/2026By Prakhar Bhatia
FastAPI on Cloudflare Python Workers: Production Guide

FastAPI can now run on Cloudflare Workers without translating the application into JavaScript. Python Workers reached general availability on September 21, 2026, with an ASGI connector for FastAPI and access to Workers bindings such as D1, R2, Workers AI, Durable Objects, Queues, Workflows, and Hyperdrive.

The deployment target still differs sharply from a Linux container. CPython runs as WebAssembly through Pyodide inside Cloudflare's V8 isolate runtime. There is no durable local disk, native package support depends on WebAssembly-compatible wheels, and request work must fit Workers limits. Database drivers travel through a socket bridge rather than a conventional host network stack.

The right question is therefore not whether a FastAPI app can start. It is whether the app's packages, state, background work, and operational assumptions match the runtime.

What became generally available

Cloudflare's Python Workers GA announcement made Python a first-class Workers language. The release covers common frameworks including FastAPI, Django, and Flask, improves Python-to-JavaScript value conversion, adds ASGI and WSGI connectors, and expands HTTP and socket compatibility for libraries that previously assumed a conventional Python host.

Cloudflare also describes support for packages such as OpenAI, LangChain, and the Model Context Protocol SDK. That matters for AI-facing APIs, but compatibility should still be tested at the exact package versions in your lockfile.

For FastAPI, the core integration is small. The ASGI adapter turns the application into the default Worker entrypoint:

from fastapi import FastAPI
from workers import asgi

app = FastAPI()

@app.get("/health")
async def health():
    return {"status": "ok"}

Default = asgi.entrypoint(app)

This is genuine FastAPI routing and validation, not a lookalike API. The adapter handles the boundary between the Workers fetch event and ASGI.

How CPython runs inside a Worker

Python Workers use CPython compiled to WebAssembly as part of Pyodide. That WebAssembly module runs inside the same V8 isolate model used by other Workers languages. Cloudflare explains the lifecycle in its Python runtime architecture.

At deployment, Cloudflare uploads the source and packages, validates the application, executes top-level imports, and snapshots the WebAssembly linear memory. When an isolate is created for traffic, the runtime restores that snapshot instead of repeating the full interpreter and import startup sequence.

This changes how to think about initialization:

  • Top-level imports and deterministic setup are candidates for the deployment snapshot.
  • Request-specific data must stay inside the request path.
  • Open connections, secrets, timestamps, and random values should not be treated as deployment-time constants.
  • A warm isolate may serve more than one request, so mutable globals can leak state between requests.

The snapshot reduces startup work, but it does not remove application CPU cost. Pydantic validation, JSON encoding, cryptography, and user code still consume CPU time.

Start a new FastAPI Worker

Cloudflare's current Python tooling uses pywrangler. The documented initializer is:

uvx --from workers-py pywrangler init

Run locally and deploy with:

uv run pywrangler dev
uv run pywrangler deploy

A minimal pyproject.toml for the current FastAPI path can look like this:

[project]
name = "edge-api"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
  "fastapi>=0.116,<1",
  "workers-py",
  "workers-runtime-sdk",
]

The Workers compatibility date selects runtime behavior, including the Python version. Cloudflare documents Python 3.14 as the default for compatibility dates on or after September 8, 2026. Pin a compatibility date, test upgrades deliberately, and avoid treating a date change as routine metadata.

Design the entrypoint as an adapter

Keep the Worker-specific entrypoint thin. The application should separate transport, domain logic, and binding access so that most tests can run in ordinary Python.

from fastapi import Depends, FastAPI, HTTPException
from workers import asgi

from app.orders import OrderService
from app.runtime import get_order_service

app = FastAPI(title="Orders API")

@app.get("/orders/{order_id}")
async def get_order(
    order_id: str,
    service: OrderService = Depends(get_order_service),
):
    order = await service.find(order_id)
    if order is None:
        raise HTTPException(status_code=404, detail="Order not found")
    return order

Default = asgi.entrypoint(app)

This structure makes it possible to substitute a local repository in unit tests and a D1, R2, or Hyperdrive implementation in Workers. It also prevents Cloudflare binding calls from spreading through every route handler.

FastAPI lifespan hooks and middleware deserve targeted tests. Do not assume process startup and shutdown semantics match a long-running Uvicorn process. Put durable coordination in a proper service rather than relying on one isolate staying alive.

Audit package compatibility before migrating

Package compatibility is the first serious migration gate. Cloudflare supports pure Python packages, packages included in Pyodide, and packages that publish compatible PyEmscripten wheels. A package with a platform-specific C, C++, Rust, or Fortran extension cannot use an ordinary Linux wheel inside the WebAssembly runtime.

PEP 783 standardizes platform tags for Emscripten wheels. It gives maintainers and build tools a consistent way to publish packages for this target. Acceptance of the PEP improves the path, but it does not mean every native dependency already ships a compatible wheel.

Audit the complete transitive dependency graph:

uv tree
uv lock --check

For each package with native code, look for a PyEmscripten wheel or a documented Pyodide package. Test imports in pywrangler dev, then deploy a preview and test again. Local CPython success on macOS or Linux does not prove Workers compatibility.

Pay special attention to image processing, scientific computing, cryptography, database drivers, XML parsers, and packages that shell out to host executables. Where a dependency is unavailable, the practical choices are to replace it, move that operation to another service, or keep the workload on containers.

Know the standard-library boundaries

Most of the Python standard library is available, but Cloudflare lists modules that are absent because they depend on unsupported operating-system behavior. The current list includes curses, dbm, ensurepip, fcntl, grp, idlelib, lib2to3, msvcrt, pwd, resource, syslog, termios, tkinter, turtle, venv, and winreg.

The filesystem is ephemeral. Code can use files for short-lived request processing, but those files are not durable and may disappear with the isolate. Do not use SQLite files, uploaded media directories, lock files, or local caches as persistent application state.

Use Workers storage services instead:

  • D1 for relational data that fits its model.
  • R2 for objects and uploaded files.
  • KV for read-heavy key-value configuration and cache-like data.
  • Durable Objects for coordinated state with a single logical owner.
  • An external PostgreSQL or MySQL database through Hyperdrive.

This is a larger architectural difference than the ASGI adapter. Our comparison of Python hosting options is useful if the application depends on a full operating system or long-running processes.

Connect FastAPI to PostgreSQL or MySQL

Hyperdrive provides connection pooling close to Workers and reduces the cost of repeatedly establishing remote database connections. Python Workers access the database through a socket bridge.

Cloudflare's Python Hyperdrive examples currently list tested PostgreSQL drivers including asyncpg, pg8000, and psycopg, plus MySQL drivers such as aiomysql and pymysql. Cloudflare also notes that low-level socket behavior can differ from a normal host.

Your Worker configuration binds Hyperdrive:

{
  "compatibility_date": "2026-09-23",
  "compatibility_flags": ["python_workers"],
  "hyperdrive": [
    {
      "binding": "HYPERDRIVE",
      "id": "your-hyperdrive-id"
    }
  ]
}

Then the application obtains the binding through the Workers runtime API and passes its connection details to the driver. Keep credentials out of logs and error responses.

Connection pooling does not move the database. A database in one region can still add network latency for globally distributed requests. Hyperdrive removes connection setup overhead and can cache eligible reads, but write latency and transactional work still travel to the database.

Be precise about async database behavior

FastAPI makes asynchronous route handlers easy to write, but every library beneath them must also behave correctly. Cloudflare documents that asynchronous socket operations do not block the event loop. Synchronous operations need locking because concurrent access can corrupt protocol state.

Cloudflare currently documents only synchronous SQLAlchemy support in this environment. Async SQLAlchemy depends on greenlet, which is not supported on the documented path. That is a good example of why framework compatibility does not imply stack compatibility.

For a migration, test:

  • Connection acquisition and release under concurrent requests.
  • Transaction rollback after exceptions.
  • Query cancellation and timeouts.
  • Pool behavior after an upstream connection reset.
  • Driver handling of TLS and database certificates.
  • Pydantic serialization of database-specific types.

Do not hide blocking calls inside async def. If the chosen driver is synchronous, isolate the access pattern, measure it, and confirm it fits the Worker execution model.

Serve static assets without routing everything through Python

Cloudflare's FastAPI documentation supports a static ASSETS binding. This is useful for API documentation assets, a small front end, or files shipped with the application.

Configure assets so that known files are served directly and unmatched paths reach the Worker:

{
  "assets": {
    "directory": "./public",
    "binding": "ASSETS",
    "run_worker_first": ["/api/*", "/docs*", "/openapi.json"]
  }
}

Use the Worker for dynamic authorization or route handling, not as an expensive file server. If a single-page application needs a fallback document, make that catch-all explicit and test that API 404 responses do not accidentally return HTML.

This architecture differs from deploying FastAPI behind a CDN on a conventional platform. Our guide to FastAPI static files and CDN deployment covers that separate pattern.

Use Workers bindings through the supported bridge

Python code can access JavaScript globals and bindings through the foreign-function interface, but Cloudflare recommends the higher-level workers module where it provides an API. Use direct Pyodide conversion only when necessary.

The bridge makes D1, R2, KV, Queues, Workers AI, and other bindings available without an HTTP hop. Keep the conversion boundary narrow. Convert values once, validate them, and return ordinary Python objects to domain code.

For a file upload, for example, stream or bound the input, validate its declared and actual type, then store it in R2. Do not read an unbounded body into WebAssembly memory. The same rule applies to large JSON requests and model outputs.

If a binding returns a JavaScript object that does not behave like a Python mapping, normalize it at the repository boundary. This keeps route handlers readable and reduces surprises during testing.

Keep validation costs visible

FastAPI and Pydantic can express rich request and response models, but validation is application work. Deeply nested unions, large lists, custom validators, and repeated model conversion consume CPU and memory. Use strict bounds on collection sizes and text lengths. Avoid validating a large payload several times as it crosses route, service, and storage layers.

Return response models when they protect an external contract, especially when internal objects contain fields that must not leave the service. For hot internal endpoints, measure whether a simpler schema provides the same safety with less work. Performance tuning should never remove authorization checks or allow secret fields to escape.

Generate and review the OpenAPI document in CI. A dependency or Pydantic upgrade can alter schemas without breaking unit tests. Store a normalized contract artifact and require an intentional review for changes that affect clients.

Treat authentication as an edge responsibility

Authentication code is a good fit for a globally distributed request layer when it performs bounded signature verification and policy checks. Keep key discovery, issuer validation, audience validation, clock tolerance, and algorithm allowlists explicit. Never select an algorithm solely from an untrusted token header.

Cache public verification keys with a documented lifetime and a recovery path for rotation. A stale-key failure should be distinguishable from an invalid-token failure in internal telemetry, while the public response remains restrained. Rate-limit authentication failures before expensive downstream work.

Authorization belongs close to the resource decision. A valid token does not prove that a user may read an order or write an R2 object. Carry a small, validated identity object into domain services and apply tenant checks at the data boundary.

Fit the workload to Workers limits

Cloudflare's current Workers limits list 128 MB of memory per isolate and a 64 MiB Worker size limit. Free requests have a much smaller CPU allowance than paid plans. Paid Workers can configure a larger CPU limit, with five minutes as the documented maximum and 30 seconds as the default.

Cloudflare reports an average Worker startup time of 2.2 milliseconds and notes that heavier authentication or server-rendered applications may use 10 to 20 milliseconds. Those are platform-level figures, not a promise for a particular FastAPI application. Measure your package set, validation models, and request paths.

Good fits include:

  • JSON APIs with bounded payloads.
  • Authentication and authorization edges.
  • Webhook validation and routing.
  • Read-heavy endpoints backed by cacheable data.
  • AI request gateways and lightweight orchestration.
  • APIs that benefit from globally distributed request handling.

Poor fits include CPU-heavy media work, large scientific models, host executables, durable local processes, and tasks that require unsupported native packages. Move long-running multi-step work into Workflows or Queues where the product semantics fit, rather than keeping one HTTP request open.

Test in three layers

An ordinary FastAPI unit suite is still valuable. Use dependency overrides to test validation, authorization, and domain behavior without the Workers runtime.

from fastapi.testclient import TestClient

from app.main import app

client = TestClient(app)

def test_health():
    response = client.get("/health")
    assert response.status_code == 200
    assert response.json() == {"status": "ok"}

The second layer runs with pywrangler dev. Cloudflare's local development environment uses the Workers runtime and simulates local resources by default. Remote bindings are available when local simulation cannot reproduce an integration, though they are slower and must never point destructive tests at production.

The third layer deploys a preview or non-production Worker and runs smoke, contract, and load tests against it. Verify headers, streaming behavior, cancellation, database reconnection, and error serialization. Record the compatibility date with every result.

Test failure behavior, not only happy paths

Simulate a database timeout, a closed upstream connection, an unavailable binding, malformed JSON, an oversized upload, and a cancelled client request. Confirm that the API returns stable status codes without exposing connection strings, SQL text, stack traces, or Worker internals.

Test concurrency with realistic payloads rather than a synthetic empty handler. Watch CPU time, memory, subrequests, database connections, and tail latency. A route can have a fast median while timing out under a burst because each request opens a fresh database connection or builds a large model graph.

For streaming responses, verify the first-byte time and what happens when the client disconnects. Ensure downstream work is cancelled where possible. If work must survive the request, move it to a queue or workflow and return a durable operation identifier.

Instrument the application boundary

Add a request identifier at the Worker edge and propagate it to database calls and outbound requests. Log structured events with route templates rather than raw URLs, because raw paths and query strings may contain identifiers or secrets. Record status, duration, CPU-relevant phase timings, and dependency outcomes.

Keep Pydantic validation failures separate from application exceptions and infrastructure failures. This makes a spike in bad client requests distinguishable from a broken database. Sample successful requests if volume is high, but retain enough data to compare deployed versions.

Metrics should answer concrete questions: which routes consume the most CPU, where database waits occur, how often isolates initialize, which package upgrade changed bundle size, and whether errors correlate with one compatibility date. Observability that cannot guide a rollback or a fix becomes cost without control.

Plan an incremental migration

Moving a mature FastAPI application all at once creates too many unknowns. Start with an inventory:

  1. Export the direct and transitive dependency graph.
  2. Find native extensions and host-level calls.
  3. List every filesystem read and write.
  4. Classify database drivers and ORM features.
  5. Identify background tasks, schedulers, and process globals.
  6. Measure payload sizes, CPU-heavy routes, and peak memory.
  7. Map outbound hosts and authentication requirements.

Choose one stateless, well-observed route group for the first deployment. Put it behind a traffic control that can return requests to the existing service. Compare correctness and latency using real request shapes, without copying sensitive data into test environments.

Expand only after the boring operational cases work: rollback, credential rotation, logs, tracing, database failover, and dependency upgrades. A successful demo endpoint is the beginning of the migration, not its proof.

Production readiness checklist

Before sending customer traffic to FastAPI on Python Workers, verify:

  • The compatibility date and Python dependencies are pinned.
  • Every native dependency has a working PyEmscripten or Pyodide path.
  • No route assumes a durable local filesystem.
  • Mutable global state is absent or safe across requests.
  • Request bodies and uploaded files have hard limits.
  • Database timeouts, transactions, and reconnection are tested.
  • Hyperdrive points to the intended environment and region.
  • Secrets use Worker bindings and never enter response bodies or traces.
  • Long-running work moves to Queues or Workflows where appropriate.
  • Static assets bypass Python unless dynamic handling is required.
  • Unit, local-runtime, and deployed integration tests all pass.
  • CPU, memory, startup, and bundle size are measured with production-like inputs.
  • A rollback route to the previous service has been rehearsed.

Python Workers make FastAPI a credible edge deployment option, especially for teams that want Python application code next to Cloudflare's network and bindings. The runtime rewards applications that are stateless at the request layer, explicit about dependencies, and disciplined about external state.

Sources and freshness

This guide was verified on September 23, 2026 using Cloudflare's Python Workers GA announcement, Python Workers documentation, runtime architecture, FastAPI package guide, package support, standard-library reference, foreign-function interface, Hyperdrive Python examples, and the official PEP 783 specification. Check current package and compatibility references before a production migration because this ecosystem is moving quickly.


FAQs

Can FastAPI run on Cloudflare Workers?

Yes. Python Workers are generally available and include an ASGI connector that exposes a FastAPI application as a Worker entrypoint.

Does Cloudflare run a normal Python process?

No. Cloudflare runs CPython compiled to WebAssembly through Pyodide inside the Workers V8 isolate runtime, then restores a deployment-time memory snapshot for requests.

Which Python version does Cloudflare Workers use?

The version is controlled by the Workers compatibility date. Cloudflare documents Python 3.14 as the default for compatibility dates on or after September 8, 2026.

Can FastAPI on Workers connect to PostgreSQL or MySQL?

Yes. Python Workers can connect through Hyperdrive and its socket bridge. Cloudflare documents tested PostgreSQL and MySQL drivers, but driver and ORM compatibility still needs verification.

Do all PyPI packages work on Python Workers?

No. Pure Python packages generally work, while native extensions need compatible PyEmscripten wheels or inclusion in Pyodide. The ecosystem is growing but remains a deployment constraint.

Can a Python Worker write local files?

It can use an ephemeral filesystem within the isolate, but files are not durable and disappear with the isolate. Use R2, D1, KV, or an external database for persistent state.

Should an existing FastAPI monolith move to Workers unchanged?

Usually not. Start with stateless endpoints, authentication edges, webhooks, or read-heavy APIs, then move only after auditing packages, database behavior, background work, CPU, memory, and filesystem assumptions.

🚀

Work with us

Let's build something together

We build fast, modern websites and applications using Next.js, React, WordPress, Rust, and more. If you have a project in mind or just want to talk through an idea, we'd love to hear from you.

Related Articles


Live Chat