Lazy, on-demand loading of FastAPI routers, mounted on the first matching request
Project description
fastapi-router-lazy
Lazy, on-demand loading of FastAPI routers.
Large FastAPI applications pay for every router at startup: importing the
module, building each route's dependency graph and response model, generating
its OpenAPI schema. fastapi-router-lazy mounts a tiny stub per route and
loads the real router only on the first request matching one of its paths.
The full startup win — unused router modules are never imported — comes from generating the route metadata ahead of time and shipping it, so the app reads that cache at startup instead of importing every module. The default in-process extractor is the simplest wiring, but it imports each module at startup to read its routes: it mounts on demand without deferring the imports. The documentation covers which strategy defers imports.
The core needs nothing but FastAPI and works with plain fastapi.APIRouter.
Install
pip install fastapi-router-lazy
# variant/version-aware extraction:
pip install "fastapi-router-lazy[variants]"
Usage
The examples below use "myapp" as the name of your importable Python
package — the one the extractor walks to find modules named router.py, each
exposing an APIRouter:
myapp/ # <- the package name you pass to route_infos_extractor
├── __init__.py
├── users/
│ └── router.py # exposes `router = APIRouter()`
└── items/
└── router.py
Given that layout, lazy loading is two steps.
1. Generate the route metadata (at build time — imports each module once and
writes routes.json):
from pathlib import Path
from fastapi_router_lazy import route_infos_extractor
route_infos_extractor("myapp", cache=True, cache_file=Path("routes.json"))
2. Run lazily (at runtime — reads the metadata and imports no router module until its first matching request):
from pathlib import Path
from fastapi import FastAPI
from fastapi_router_lazy import (
RouterLoader,
lazy_middleware_factory,
route_infos_extractor,
)
app = FastAPI()
# strict=True: use the prebuilt metadata, never re-import at startup.
extractor = route_infos_extractor(
"myapp", cache=True, cache_file=Path("routes.json"), strict=True
)
loader = RouterLoader(extractor, app)
middleware = lazy_middleware_factory(loader)
app.add_middleware(middleware)
# Register the stubs; real routers load on first matching request.
loader.load(middleware)
The default extractor (route_infos_extractor("myapp"), no cache) is the
simplest wiring, but it imports every module at startup to read its routes — it
mounts on demand without deferring imports. Eager loading, deployment filtering,
and the variant/version-aware extractor ([variants]) are covered in the
documentation.
Limitations
Lazy loading trades some runtime dynamism for startup speed:
- lazily-declared routes are absent from
/openapi.jsonand/docsuntil their first matching request mounts them (mount eagerly if you need a complete schema up front); - no
prefix=is applied atinclude_routertime — bake prefixes into theAPIRouteritself; - a stub and a real route sharing a path are resolved by Starlette match order.
See the Limitations section of the docs for details.
Documentation
Full documentation is available at
toilal.github.io/fastapi-router-lazy.
A preview of the in-development develop branch is published at
toilal.github.io/fastapi-router-lazy/dev/.
Requirements
Python 3.12+ and FastAPI.
License
MIT
CHANGELOG
v0.2.0 (2026-07-05)
Features
v0.1.0 (2026-07-05)
- Initial Release
Changelog entries are generated automatically by python-semantic-release from Conventional Commits on release.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_router_lazy-0.2.0.tar.gz.
File metadata
- Download URL: fastapi_router_lazy-0.2.0.tar.gz
- Upload date:
- Size: 148.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d72348a66add453e87e831715ba3e67bcb154eb991770a22b87b31e2e5cbd80
|
|
| MD5 |
9ef62e4088a17bebf06e5f2cb7fce0f1
|
|
| BLAKE2b-256 |
75f03223eb9438d8d06aac48e0ed35c5fbba00b8dc8dfaa6822066ad96ac3e30
|
File details
Details for the file fastapi_router_lazy-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_router_lazy-0.2.0-py3-none-any.whl
- Upload date:
- Size: 21.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57d50452f6e6679fd8aeeae2fcca22f3a7f48ca59a678f5ff56fea7e956ee83c
|
|
| MD5 |
c72354e12186322b1cd38cd5919c7d43
|
|
| BLAKE2b-256 |
d20bd4f41d07dce4cbc9492e25f48bcf00eeeaf750a952b1e03984c3bfbf7141
|