Skip to main content

py2axum

Compile a FastAPI + SQLAlchemy + Pydantic application ahead of time into a Rust (axum) binary — and prove, response by response, that it behaves like the Python app.

py2axum reads your FastAPI package (it never imports or runs it) and compiles every route, and the project code those routes reach, into a Rust crate. The crate runs on a small runtime that reproduces CPython, Pydantic v2, SQLAlchemy 2.0 and Starlette semantics, so that status codes, headers, JSON bodies (key order included) and 422 validation errors come out byte for byte the same. What it cannot reproduce exactly, it refuses at compile time with file:line, or leaves to a Python process that the binary relays to.

your FastAPI app ──py2axum──▶ Rust crate (axum + tokio + sqlx) ──cargo──▶ one binary, no Python at run time

Who it is for: teams running a FastAPI + PostgreSQL API in production who want lower latency, higher throughput per core or a smaller memory footprint, without rewriting the service or giving up Python for development, tests and debugging. The Python application stays the source of truth; the binary is a build artifact.

What you get

Measured on the example application, examples/bookshelf (users, JWT auth, books, reviews, a WebSocket), its database seeded with 1 000 books and 3 000 reviews: FastAPI on uvicorn (4 workers) against the binary (4 threads), same PostgreSQL, same machine (Apple M1 Pro, 10 cores), the two servers alternated run by run. Latency seen by one client, median of 3 × 5 s:

Endpoint FastAPI + uvicorn py2axum binary
GET /books/{id}: book, owner, reviews (2 queries) 1.94 ms (p99 16.0) 0.50 ms (p99 1.6) ×3.9
GET /books?limit=20 1.84 ms (p99 14.6) 0.67 ms (p99 3.2) ×2.7
GET /books?tag=sf&limit=20 (JSONB @>) 1.85 ms (p99 12.8) 0.79 ms (p99 5.4) ×2.4
GET /books/stats (GROUP BY, avg) 2.02 ms (p99 14.0) 0.65 ms (p99 2.3) ×3.1
GET /me (JWT check + 1 query) 1.02 ms (p99 10.3) 0.23 ms (p99 0.8) ×4.4
POST /books (validation + INSERT) 2.72 ms (p99 15.5) 0.54 ms (p99 1.7) ×5.1
POST /auth/register, invalid (FastAPI's 422) 0.44 ms (p99 1.5) 0.08 ms (p99 0.2) ×5.6
Memory (RSS at rest) 470 MB (4 processes) 12 MB

With 64 concurrent clients, the binary served about 2 to 4 times as many requests on GET /books/{id} and the lists, and 5 to 6 times as many invalid ones; on the endpoints dominated by PostgreSQL (the aggregate, the INSERT) the ratio moved with the load of the machine, which other jobs shared during these runs. Reproduce them with python bench/bench.py --target bookshelf --interleave 3, ideally on a dedicated machine.

Gains depend on how much of your request time is Python (validation, serialization, the ORM) rather than the database. Measure your own application: the bench script and the conformance harness are in this repository.

What it does not do

  • It is not a Python interpreter. It compiles a closed, growing subset of Python and of a list of libraries. eval, metaclasses, C extensions, raw ASGI middlewares and unlisted libraries are refused, never approximated.
  • It does not run your migrations nor serve the OpenAPI /docs pages: run Alembic as usual, and keep the docs on your Python deployment.
  • PostgreSQL only (through sqlx). FastAPI, Pydantic, SQLAlchemy and Python must be within the tested version ranges, read from your lock file.
  • It is alpha. Each supported behaviour is verified by differential tests, but your application combines them its own way: run a conformance check on it before production.

Quick start

pip install py2axum                  # Python ≥ 3.12, no dependencies; you also need Rust (rustup) and PostgreSQL

py2axum check app --root .           # route by route: native, python-side or refused (with file:line)
py2axum app --root . --python-side auto -o build/api --name api
cargo build --release --manifest-path build/api/Cargo.toml
DATABASE_URL=postgresql://localhost/mydb PY2AXUM_PYTHON_URL=http://127.0.0.1:8000 ./build/api/target/release/api

app is the package holding the FastAPI application and --root the directory you run uvicorn from. --python-side auto leaves the routes that do not translate to your Python application, which the binary relays to at PY2AXUM_PYTHON_URL; without it, generation fails on the first refused route.

$ py2axum check examples/bookshelf/app --root examples/bookshelf
native       POST /auth/login               examples/bookshelf/app/routers/auth.py:26
native       GET /books                     examples/bookshelf/app/routers/books.py:39
refused      GET /books/export.zip          examples/bookshelf/app/routers/export.py:18
             └ examples/bookshelf/app/routers/export.py:26: library call `zipfile.ZipFile()` is not supported (not in the py2axum library map)
native       WEBSOCKET /ws/books/{book_id}  examples/bookshelf/app/routers/live.py:43
...
12/13 routes native (92.3 %), 0 python-side, 1 refused — generation would fail
hint: --python-side auto leaves the refused routes to a Python process next to the binary

The getting-started guide walks through the example end to end: check, build, run, hybrid mode, comparison with FastAPI, Docker, runtime configuration, graceful shutdown and Sentry.

Why trust the binary

  • Differential testing. The same requests go to FastAPI and to the binary; status, headers and bodies must match byte for byte. The repository's suites run about 1 300 such requests, the bookshelf example 75 of its own, and tests/conformance.py runs yours, from a scenario you write, recorded traffic or requests generated from your OpenAPI schema.
  • Refuse rather than guess. A construct outside the subset stops the translation with file:line; it is never translated approximately. Every known difference from CPython is documented.
  • No rewrite, no fork. Unit tests, local development, debugging and the OpenAPI docs keep running on Python. A route py2axum cannot handle stays in Python (--python-side) and the binary relays it, so one deployment serves both.

What is supported

A summary; the full list, with every documented difference, is in docs/supported.md.

  • FastAPI / Starlette: routes and routers (prefixes, factories, conditional registration), path, query, header, body, form and file parameters with FastAPI's exact 422 errors, dependencies (Depends, yield, per-request cache, Annotated, OAuth2/HTTPBearer/HTTPBasic), response_model, Response objects, StreamingResponse/SSE, BackgroundTasks, exception handlers, middlewares (CORSMiddleware, GZipMiddleware, BaseHTTPMiddleware, @app.middleware("http")), lifespan, WebSockets, graceful shutdown.
  • Pydantic v2: lax-mode validation with pydantic-core's error types and messages, unions, enums, Field constraints and aliases, field_validator/model_validator, computed_field, model_dump/model_validate, TypeAdapter, EmailStr and URL types, pydantic-settings.
  • SQLAlchemy 2.0 (async and sync sessions, PostgreSQL): declarative models, JSON/JSONB, enums, Numeric, TypeDecorator, the identity map, autoflush, savepoints, relationships and loader strategies, select/update/delete/insert ... on conflict, joins, subqueries, aggregates, create_all.
  • Python: functions, closures, decorators, classes, dataclasses, exceptions, comprehensions, generators, match, asyncio, and much of the standard library (datetime, decimal, uuid, re, json, csv, hashlib, hmac, base64, urllib.parse...).
  • Libraries: httpx, aiohttp, redis.asyncio, aio-pika, PyJWT and python-jose (HMAC), bcrypt, pyotp, itsdangerous, cryptography's Fernet, jinja2, aiosmtplib, sentry-sdk, prometheus_client, tenacity, nh3, pywebpush, google-auth id tokens, python-dateutil, xmltodict.

How it works

  1. Frontend: indexes the package's modules and imports statically (ast), finds the FastAPI app, routers, routes, models and schemas.
  2. Compiler: every reachable project function is compiled to Rust over a dynamic value type with CPython semantics; library calls go through a closed map, anything unlisted is refused.
  3. Runtime (Rust, copied into each generated crate): values and operators, Pydantic validation and serialization, the SQLAlchemy session and SQL compiler on sqlx, Starlette's middleware and routing, the supported libraries.

Details, and how this differs from RustPython: docs/how-it-works.md.

Documentation

Getting started from pip install to a deployed binary, step by step
Supported subset what translates, version ranges, every known difference
Conformance check that the binary answers like your application
How it works the compiler, the runtime, hybrid deployments
Docker multi-stage builds, caching, the hybrid setup
Changelog what changed in each release

Project layout

py2axum/            the transpiler (Python, standard library only) and the Rust runtime it embeds
examples/           bookshelf (the example of this page), notes (a smaller one), docker (reference build)
fixtures/           reference applications exercising the supported subset (used by the test suites)
tests/              conformance harness and scenarios, rejection tests
bench/              throughput, latency and memory benchmarks
docs/               documentation

Contributing

Contributions are welcome, especially constructs from real applications that py2axum refuses. See CONTRIBUTING.md. The rule that keeps the project honest: every new behaviour comes with conformance cases comparing it with the Python reference, and every unsupported case is refused with a test.

License

Apache License 2.0, see LICENSE.

Metadata

Release files for py2axum 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for py2axum 0.4.0
File Size Uploaded
py2axum-0.4.0.tar.gz 835.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py2axum 0.4.0
File Interpreter ABI Platform
py2axum-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.5 MB

Release files / py2axum-0.4.0.tar.gz

Download URL py2axum-0.4.0.tar.gz
Size 835.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f013ac2da5402b60cb98d9c81072215f3f04f9a7efa9bcfa6b9af2295bc140cc
BLAKE2b-256 checksum
How to use checksums
1b2ea40bee19df3853cc3d02863668f6e4a9b1f483f137761307ee4d29840327
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / py2axum-0.4.0-py3-none-any.whl

Download URL py2axum-0.4.0-py3-none-any.whl
Size 649.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2609564fdfe5391089ef1349d235c75e399cf0546e0075007caf1e06c081527e
BLAKE2b-256 checksum
How to use checksums
59d43c00f61919dd82adcb8fe8eaf14764abae1c7550763fe95d77d26235cda6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page