Skip to content

Index

jero jero

A msgspec-first ASGI micro-framework for Python 3.13+.


uv add jero

What is jero?

jero is an AI-powered (a note on AI usage), msgspec-first ASGI framework where your type hints are the API contract. Routing, binding, validation, serialization, auth checks, and OpenAPI generation all derive from statically declared types, introspected once at startup. The request path stays minimal: dict lookup, msgspec decode, handler call, encode.

There are no route decorators and no dependency-injection container. Routes are plain classes (Resource for REST collections, Endpoint for one-off routes), the method name is the HTTP operation, and dependencies are ordinary constructor arguments. Everything that crosses the wire is a msgspec Struct: bodies, headers, path and query params, forms. That single contract drives validation, serialization, startup checks, schema generation, and msgspec's compiled-codec speed.

Quickstart

from msgspec import Struct

from jero import BaseApp, Resource


class WidgetPath(Struct):
    widget_id: str


class Widget(Struct):
    id: str
    name: str


class WidgetResource(Resource, path="/widgets"):
    # called as: GET /widgets/{widget_id}
    async def read_one(self, path: WidgetPath) -> Widget:
        return Widget(id=path.widget_id, name="widget-name")


class App(BaseApp):
    async def wire(self) -> None:
        self._include_resource(WidgetResource())


app = App()

No @app.get(...), no runtime route discovery: the class declares the path, and the method name declares the operation.

Run it under any ASGI server, e.g. granian:

granian --interface asgi myapp:app

New here? Start with Getting Started.

jero is fast

jero was written for speed and performance: in our four-scenario benchmark against seven frameworks across Python, Go, and Bun, jero is the fastest Python framework in every one, methodology included. → Performance

Core principles

jero makes one bet: being aggressively prescriptive, rather than flexible, is how a framework can be both extremely fast and a joy to build on.

Principle What it means
Speed Introspection happens once, at startup. The request path stays minimal and predictable.
Opinionated DX One way to do each thing. Contracts fail loud at startup with a precise WiringError, never quietly at runtime.
Strict typing Types are the contract, the validation source, and the OpenAPI source — and the public interface is checked by every major type checker.

jero leans hard into modern Python typing: PEP 695 generics (JSONResponse[Body, Headers], NDJSONStreamingResponse[Movie]), bounded type parameters with defaults, and Protocols, so a handler's signature is its schema. If you don't like typing, this isn't your framework.

For the reasoning behind those choices, read Philosophy. For a feature-by-feature contrast with other Python frameworks, read Comparison.

Highlights

  • Startup validation — invalid apps can't boot: every contract is checked at wiring with a precise WiringError.
  • Typed responses and headersJSONResponse[Body, Headers] keeps both schemas; unions of responses document every status.
  • Typed streaming — NDJSON, SSE, and raw bytes, with lifecycle teardown and disconnect handling done for you.
  • Typed WebSockets — compiled framing in both directions and bounded local fan-out through Channel.
  • Auth checked at startup — the user type is verified against the authenticator before a single request is served.
  • Reverse routingLocation / Link headers built from the route class, validated at construction.
  • Compiled middleware & CORS — fixed per-tier costs, zero on uncovered routes.
  • OpenAPI from your types — a 3.1 spec plus Scalar docs UI, no duplicate schema definitions.
  • In-process TestClient — sync, no network, full lifespan, streaming and WebSockets.

API reference

The full public surface — BaseApp, BaseFactory, Resource, Endpoint, the response and streaming types, and the test helpers — is documented in the API reference.