Flask ↗ is supported in Python Workers.
Flask applications rely on a protocol called the Web Server Gateway Interface (WSGI). This means that Flask never directly reads or writes to a socket, instead relying on the WSGI server to communicate.
Python Workers include a WSGI server ↗ which you can use with Flask applications.
You need uv ↗ and node ↗ installed.
Use this quick start to run a minimal Flask application.
-
Create
src/worker.pywith your flask application:src/worker.pypython from flask import Flask from workers import wsgi app = Flask(__name__) @app.get("/") def index(): return {"message": "Hello from Flask"} Default = wsgi.entrypoint(app) -
In the project root, create
wrangler.jsonc:{ "$schema": "node_modules/wrangler/config-schema.json", "name": "my-flask-worker", "main": "src/worker.py", // Set this to today's date "compatibility_date": "2026-08-28", "compatibility_flags": ["python_workers"] }"$schema" = "node_modules/wrangler/config-schema.json" name = "my-flask-worker" main = "src/worker.py" # Set this to today's date compatibility_date = "2026-08-28" compatibility_flags = [ "python_workers" ] -
Create a
pyproject.tomlto declare dependencies:pyproject.tomltoml [project] name = "flask-worker" version = "0.1.0" requires-python = ">=3.12" dependencies = [ "flask", ] [dependency-groups] dev = [ "workers-py", "workers-runtime-sdk", ] -
Start the local development server:
uv run pywrangler dev -
In another terminal, send a request to the Worker:
curl http://localhost:8787/The Worker returns:
{"message":"Hello from Flask"}
You can serve any static frontend alongside your flask backend by using Workers Static Assets. Using Static Assets means your frontend files are not bundled inside the Worker itself, keeping the bundle small.
Place your static files in a directory such as ./public/. Then configure your
Wrangler file with an assets block that includes a binding and sets
run_worker_first to true. This ensures every request reaches your FastAPI
Worker first, so your API routes take priority over static files.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-flask-worker",
"main": "src/worker.py",
// Set this to today's date
"compatibility_date": "2026-08-28",
"compatibility_flags": ["python_workers"],
"assets": {
"directory": "./public/",
"binding": "ASSETS",
"run_worker_first": true
}
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "my-flask-worker"
main = "src/worker.py"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "python_workers" ]
[assets]
directory = "./public/"
binding = "ASSETS"
run_worker_first = trueThe following Worker handles an API route before forwarding other requests. The catch-all handlers return each asset's body, status, and headers:
from flask import Flask, Response, request
from pyodide.ffi import run_sync
from workers import wsgi
app = Flask(__name__)
@app.get("/api/hello")
def api_hello():
return {"message": "Hello from the API"}
@app.get("/")
@app.get("/<path:path>")
def frontend(path=""):
assets = request.environ["workers.env"].ASSETS
asset_response = run_sync(assets.fetch(f"https://assets.local/{path}"))
body = run_sync(asset_response.bytes())
return Response(
body,
status=asset_response.status,
headers=asset_response.headers,
)
Default = wsgi.entrypoint(app)run_sync bridges both asynchronous asset operations into Flask's synchronous
handler. API routes take priority, and unmatched paths are served from
./public/.
Run the Flask todo example from the python-workers-examples repository.
-
Clone the examples repository:
git clone https://github.com/cloudflare/python-workers-examples -
Enter the Flask todo example directory:
cd python-workers-examples/flask-todo -
Initialize the local D1 database from
db_init.sql:uv run pywrangler d1 execute todos --local --file db_init.sql -
Start the local development server:
uv run pywrangler dev