Flask
Mount pyRPC on a Flask application using mount_flask.
The Flask adapter mounts pyRPC onto a Flask app. Flask is sync-only, so the adapter handles async procedure execution internally, your procedure code stays the same.
1. Install
uv add pyrpc-core[flask]
# or
pip install "pyrpc-core[flask]"This also installs flask-cors, which you'll need for local frontend development.
2. Write the server
from flask import Flask
from flask_cors import CORS
from pyrpc_core import rpc
from pyrpc_flask import mount_flask
app = Flask(__name__)
CORS(app, origins=["http://localhost:3000"]) # your frontend origin
@rpc.query
def greet(name: str = "World") -> dict:
return {"message": f"Hello, {name}!", "framework": "Flask"}
@rpc.query
def read_item(item_id: int, q: str = None) -> dict:
return {"item_id": item_id, "q": q}
@rpc.mutation
def create_item(name: str, description: str = None) -> dict:
return {"name": name, "description": description, "created": True}
mount_flask(app)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)3. Start the dev server
pyrpc devFirst run: a short wizard asks for your backend framework (Flask is preselected when detected) and entry point, then client root and frontend framework, and writes pyrpc.json. Every run after: reads pyrpc.json automatically. To skip the wizard:
# auto-detect
pyrpc dev --yes
# fully explicit
pyrpc dev --yes --framework flask --module main --client ../clientpyrpc dev serves the app with Flask's own dev server (flask run on your module:app - no WSGI-to-ASGI bridge involved; default http://127.0.0.1:8000/rpc), generates __pyrpc.ts at the client project root, and re-generates it on every .py save.
4. Connect the frontend
import { createReactClient, httpBatchLink } from "@pyrpc/react"
import type { Types } from "@pyrpc/types"
export const api = createReactClient<Types>({
links: [
httpBatchLink({
url: "http://localhost:8000",
}),
],
})Note: the URL must match the port your Flask app is served on. pyrpc dev uses port 8000 by default; if you run the app directly with app.run(port=5000) instead, use 5000.
See React, Next.js, Vue, or Svelte for full frontend setup.
How it works
@rpc.query/@rpc.mutationregister the function in the global registry with its kind.mount_flask(app)adds two routes to the Flask app:POST /rpc: procedure dispatch (async execution viaanyio.run)GET /rpc: schema introspection
- Flask is sync-only,
mount_flaskruns async procedure execution withanyio.runinternally. You don't need to change anything.
CORS origins by frontend
| Frontend | Default dev origin |
|---|---|
| React (CRA) | http://localhost:3000 |
| React (Vite) | http://localhost:5173 |
| Next.js | http://localhost:3000 |
| Vue (Vite) | http://localhost:5173 |
| Svelte (Vite) | http://localhost:5173 |
Full working examples
| Example | Frontend | Source |
|---|---|---|
| Flask + React | React + TanStack Query | examples/flask-react |
| Flask + Next.js | Next.js App Router + RSC | examples/flask-nextjs |
| Flask + Vue | Vue 3 + TanStack Vue Query | examples/flask-vue |
| Flask + Svelte | Svelte + TanStack Svelte Query | examples/flask-svelte |

pyRPC