Getting Started with Python Workers

Python Workers brings first-class Python support to Cloudflare's edge network. Deploy globally distributed Python applications with zero containers, no Kubernetes, and no cold starts worth worrying about.

Your First Python Worker

A Python Worker is as simple as defining an on_fetch handler. This is the entry point for every HTTP request:

from js import Response

async def on_fetch(request):
    return Response.new("Hello from Python on the edge!")

That's it. That's a globally deployed Python application. No containers, no WSGI servers, no infrastructure to manage.

What's Included

Python Workers come with a rich set of capabilities out of the box:

The on_fetch Handler

The on_fetch handler is an async function that receives a Request object and returns a Response. You can access request properties like URL, method, headers, and body:

from js import Response, env

async def on_fetch(request):
    url = request.url
    method = request.method
    headers = dict(request.headers)

    if url.pathname == "/health":
        return Response.json({
            "status": "healthy",
            "method": method
        })

    return Response.new("Hello, World!")

Environment Bindings

Cloudflare services are accessed through environment bindings. Import env from js to access KV, R2, D1, Queues, AI, and more:

from js import Response, env

async def on_fetch(request):
    # Access KV
    value = await env.KV.get("my-key")

    # Access D1 database
    results = await env.DB.prepare("SELECT * FROM users").all()

    # Access R2 bucket
    object = await env.BUCKET.get("file.txt")

    # Access AI
    response = await env.AI.run("@cf/meta/llama-3-8b-instruct",
        messages=[{"role": "user", "content": "Hello"}]
    )

    return Response.json({"data": results})

Wrangler Configuration

Configure your Worker's bindings in wrangler.toml:

name = "my-python-worker"
main = "main.py"
compatibility_date = "2024-01-01"

[[kv_namespaces]]
binding = "KV"
id = "your-kv-namespace-id"

[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-bucket"

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-database-id"

[ai]
binding = "AI"

Development Setup

Get up and running with local development using Wrangler:

# Install wrangler (once)
bun install -g wrangler

# Local development with hot reload
wrangler dev main.py

# Run tests — just regular Python
python -m pytest

# Deploy to production (30 seconds to global deployment)
wrangler deploy

FastAPI Integration

FastAPI works natively in Python Workers. Your existing FastAPI knowledge transfers directly:

from fastapi import FastAPI
from js import Response

app = FastAPI()

@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
    result = await env.DB.prepare(
        "SELECT * FROM users WHERE id = ?"
    ).bind(user_id).first()
    return {"user": result}

# That's it. Deploy with: wrangler deploy

Secrets Management

Store sensitive values securely with Wrangler secrets:

# Set secrets (encrypted at rest)
wrangler secret put DATABASE_URL
wrangler secret put API_KEY

# Access in code
async def on_fetch(request):
    db_url = env.DATABASE_URL  # Securely injected

Why Python Workers?