RYNE
Fast, secure, full-stack Python backend framework with a native Rust core.
Write your entire application in pure Python. RYNE runs the HTTP server (HTTP/1.1 + HTTP/2, native TLS), routing, JSON, validation, the SQLite driver and cryptography in compiled Rust — and installing it never requires a Rust toolchain:
pip install ryne
Why RYNE
| Goal | How RYNE delivers it |
|---|---|
| Python-only install | Prebuilt wheels (CPython 3.10+, Windows / Linux / macOS, abi3) bundle the Rust core via PyO3. |
| Native Rust core | hyper + tokio event loop, trie router, JSON, schema validation, SQLite and argon2 — all native. |
| Developer experience | Django-style models, migrations, decorators, a CLI with hot reload, and a built-in test client. No Rust knowledge needed, ever. |
| Full-stack | REST API, WebSockets, Jinja2 templates, static files, uploads, ORM, migrations, authentication, revocable sessions, CORS — admin panel and PostgreSQL on the roadmap. |
| Performance-first | Rust owns the socket, serializes responses, serves statics and runs WebSockets; Python is invoked exactly once per request. |
| Security-first | Native TLS (rustls), rate limiting, backpressure, signed CSRF, revocable sessions, argon2id, parameterized SQL, request IDs and access logs — safe defaults everywhere. |
Benchmarks
11 frameworks × 6 scenarios × 60 seconds per test, oha load generator,
50 concurrent connections, identical endpoints and payloads
(full methodology and complete tables).
| scenario | RYNE | Sanic | Starlette | Litestar | FastAPI | Flask | Django |
|---|---|---|---|---|---|---|---|
| json | 30 636 | 14 532 | 9 180 | 8 059 | 5 629 | 3 942 | 1 578 |
| plaintext | 27 829 | 12 881 | 9 098 | 7 546 | 6 447 | 4 281 | 925 |
| router | 27 472 | 10 984 | 8 168 | 6 861 | 4 641 | 3 995 | 988 |
| http | 22 333 | 12 506 | 7 347 | 6 159 | 4 316 | 3 929 | 1 281 |
| db (SQLite) | 7 348 | 2 162 | 2 104 | 2 520 | 1 625 | 1 488 | 1 323 |
| validation | 17 066 | 9 640 | 6 516 | 5 366 | 4 503 | 3 621 | 1 004 |
| peak RAM (db) | 38 MB | 79 MB | 73 MB | 204 MB | 87 MB | 115 MB | 125 MB |
How to read this. RYNE is the fastest full-featured Python framework in all six scenarios — 1.9–2.7× ahead of the runner-up (Sanic), 3.5–5.4× ahead of FastAPI, 7–30× ahead of Flask and Django — while using the least memory (now with WebSockets, templates, statics and uploads built in). Native Rust frameworks (Actix, Axum, Hyper, Rocket) are still 3–6× faster than RYNE: that is the honest price of running user code in Python, and the trade-off RYNE makes to stay a pure-Python framework.
Quickstart
pip install ryne
ryne startproject mysite
cd mysite
ryne makemigrations && ryne migrate
ryne run --reload
Or in a single file:
from ryne import Ryne
app = Ryne()
@app.get("/hello/{name}")
async def hello(request, name: str):
return {"message": f"Hello, {name}!"}
app.run() # ryne run hello:app
The full stack
Validation — compiled to Rust at import time
import enum
from ryne import HTTPException
from ryne.validation import Schema, Str, Int, List, Enum, Object
class Color(enum.Enum):
RED = "red"
BLUE = "blue"
class Address(Schema):
city: Str(max_length=80)
class CreateArticle(Schema):
title: Str(min_length=1, max_length=200)
tags: List(Str(), max_items=10) = []
views: Int(ge=0) = 0
color: Enum(Color) # -> Color.RED member on output
author: Object(nested=Address) # nested schema
nickname: Str(max_length=30) = None # optional + nullable
@app.post("/articles")
async def create_article(request):
data = CreateArticle.validate_body(request) # parse+validate in Rust, GIL-free
...
ORM + migrations — Django-style
from ryne.models import Model, CharField, IntField, ForeignKey
class Article(Model):
title = CharField(max_length=200)
views = IntField(default=0)
author = ForeignKey(Author, null=True)
article = await Article.objects.create(title="Hi")
articles = await Article.objects.filter(views__gte=1).order_by("-id").limit(10)
ryne makemigrations # schema diff -> reviewable Python migration files
ryne migrate # applied atomically, recorded in ryne_migrations
SQLite ships compiled inside the wheel: WAL mode, a read connection pool and a single serialized writer connection (in-process writes never fight over SQLite's one-writer lock). The GIL is released during every query. PostgreSQL is planned.
Auth & revocable sessions
from ryne.auth import authenticate, login, logout, logout_all, get_user, requires_login
@app.post("/login")
async def login_route(request):
user = await authenticate(request.json()["username"], request.json()["password"])
if user is None:
raise HTTPException(401)
await login(request, user) # rotates the server-side session id
return {"ok": True}
@app.post("/logout")
async def logout_route(request):
await logout(request) # revokes it server-side
return {"ok": True}
@app.get("/me")
@requires_login
async def me(request):
return {"user": (await get_user(request)).username}
Sessions are signed cookies (HMAC-SHA256, constant-time verification in
Rust) backed by a server-side registry: login rotates the session id, so
stolen pre-auth cookies are useless; logout revokes; logout_all(user_id)
kills every session of a user. Passwords are hashed with argon2id in native
code; unknown usernames cost the same as known ones (no timing oracle).
Security defaults
- Native TLS (rustls, HTTP/2 via ALPN):
ryne run --tls-cert C --tls-key K X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy,COOPon every response (opt-in HSTS and CSP)- Signed CSRF tokens for form submissions (JSON APIs unaffected)
- Per-IP rate limiting (sharded token bucket in Rust) →
429+Retry-After - Backpressure:
max_inflightcaps concurrent dispatches → instant503 - Slowloris body timeout + connection cap
- 1 MiB request-body limit, enforced mid-stream in Rust
x-request-idon every response, access log, tracebacks in debugDEBUG=Falseby default — unexpected errors never leak internals- Trusted-proxy aware client IPs (
trusted_proxies)
For blocking sync workloads: settings.sync_pool = True runs sync handlers
on a bounded blocking executor (sync_pool_size, default 64) so a slow
handler can never starve the async runtime.
WebSockets, templates, statics — the full stack
@app.websocket("/ws/{room}")
async def chat(ws, room: str):
async for message in ws:
await ws.send_text(f"{room}: {message}")
@app.get("/")
async def page(request):
return app.render(request, "index.html", posts=posts) # Jinja2
app.mount_static("/static/", "static") # served by Rust
Origin-checked handshakes, RFC 6455 framing, multipart uploads
(request.files) and typed route params ({id:int}) are all built in.
Testing
from ryne.test import TestClient
def test_hello():
with TestClient(app) as client:
assert client.get("/hello/world").json() == {"message": "Hello, world!"}
The real server (hyper, sessions, CSRF, limits) on an ephemeral port —
pip install ryne[test].
CLI
ryne startproject <name> scaffold a project
ryne run [module:app] run the server (--reload, --host, --port,
--debug, --tls-cert/--tls-key)
ryne makemigrations [--name] generate a migration from model changes
ryne migrate apply pending migrations
ryne createsuperuser create an admin user
ryne shell [module:app] interactive shell with your app loaded
ryne check [module:app] validate configuration
Documentation
Full guides live in docs/: quickstart, tutorial, validation, websockets, templates, static and uploads, ORM and migrations, auth and sessions, security (TLS deployment + hardening checklist), testing, configuration reference and performance. Runnable examples in examples/ — including a WebSocket chat and a templates demo.
Development
python -m venv .venv && .venv/Scripts/pip install -e '.[dev]'
python -m maturin develop # build the Rust core into the venv
python -m pytest # full test suite
cargo test --workspace # Rust unit tests
python -m ruff check . # lint
See CHANGELOG.md and the issue tracker for the roadmap (admin panel, templates, WebSockets, PostgreSQL).
License
MIT — see LICENSE.
Metadata
Release files for ryne 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ryne-0.4.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details for ryne-0.4.0-cp310-abi3-win_amd64.whl |
Release files / ryne-0.4.0-cp310-abi3-win_amd64.whl
| Download URL | ryne-0.4.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 3.9 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6fbe68e6066f3f0df1723f3e6461de8e0b3fd4eedef67170351b428aa21aec66
|
|
BLAKE2b-256 checksum How to use checksums |
70e4e9b328c143b0679a7ff7824ef91cc99610a43261a72bff8dc0f2f6d4f51b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Security for ryne 0.4.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.