A NestJS-style, batteries-included web framework for Python, built on top of FastAPI.
Austial
Austial gives Python the exact developer experience of NestJS:
decorator-driven modules/controllers/providers, real constructor-based
dependency injection, the full request lifecycle (guards, pipes,
interceptors, exception filters, middleware), a config layer, a database
layer, Terminus-style health checks, a testing module -- and a CLI so you can
scaffold new projects and artifacts the same way nest new/nest generate do.
This repository (austial-py) is the framework itself -- an installable
library, no bundled sample app. To see it in action, scaffold a new project
with the CLI (see Quickstart below); that generated project is
the "hello world" app, kept separate from the framework's own source tree.
Why
FastAPI is a fantastic ASGI toolkit, but it doesn't prescribe an application architecture. Austial is opinionated on top of FastAPI the way Nest is opinionated on top of Express/Fastify: modules own controllers and providers, providers get dependency-injected by type, and the request pipeline (guard → pipe → interceptor → handler → filter) is a first-class concept instead of something you hand-roll with dependencies everywhere.
Architecture at a glance
| NestJS | Austial |
|---|---|
@Module() |
@Module(imports=, controllers=, providers=, exports=) |
@Controller() / @Get() etc. |
@Controller(prefix) / @Get/@Post/@Put/@Patch/@Delete/@Options/@Head |
@Injectable() |
@Injectable(scope=Scope.DEFAULT | Scope.TRANSIENT) |
| Constructor DI | Container resolves __init__ type hints recursively, singleton by default |
NestFactory.create(AppModule) |
AustialFactory.create(AppModule) -> AustialApplication |
app.listen(3000) |
await app.listen(8000) |
CanActivate / @UseGuards |
CanActivate ABC + ExecutionContext, @UseGuards(...) |
NestInterceptor / @UseInterceptors |
NestInterceptor ABC (intercept(context, call_next)) + @UseInterceptors(...) |
PipeTransform / ValidationPipe |
PipeTransform ABC + ValidationPipe |
ExceptionFilter / @Catch |
ExceptionFilter ABC + @Catch(...), default AllExceptionsFilter |
NestMiddleware, MiddlewareConsumer |
NestMiddleware ABC, configure(consumer) on modules |
ConfigModule.forRoot() |
ConfigModule.for_root(env_file=".env") / ConfigService |
TypeOrmModule.forRootAsync |
DatabaseModule.for_root_async(use_factory=, inject=) (SQLAlchemy async) |
@nestjs/terminus |
austial.terminus.HealthCheckService + MemoryHealthIndicator, DatabaseHealthIndicator |
@nestjs/testing |
austial.testing.Test.create_testing_module(...).compile() |
nest new / nest generate |
austial new <name> / austial generate|g module|controller|service|resource <name> |
A note on file names
Nest names files with dots (health.controller.ts) because Node resolves
modules by explicit relative path strings. Python's import a.b instead
resolves a as a package and b as a submodule -- a literal file
health.controller.py isn't importable via a normal import statement. So
Austial uses underscore suffixes instead: health_controller.py,
health_service.py, health_module.py, health_dto.py. The directory
layout still mirrors Nest 1:1 -- one folder per feature under
src/modules/.
Quickstart
Austial is published on PyPI -- install the CLI and scaffold a new project:
uv tool install austial # or: pipx install austial / pip install austial
austial new my-app # scaffold a new project
cd my-app
uv sync
cp .env.example .env
uv run austial serve # http://localhost:8000, auto-reload
austial new scaffolds a small health-check "hello world" app --
GET /, GET /health, GET /health/protected, /docs (Swagger UI) -- see
Using the CLI below for the full generator reference.
Developing Austial itself
git clone https://github.com/austial/austial-py
cd austial-py
uv sync --all-extras
uv run pytest
Linting, type-checking & pre-commit hooks
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy austial tests # type-check
uv run pre-commit install --hook-type pre-commit --hook-type pre-push
uv run pre-commit run --all-files # run every hook once, on demand
Once installed, git commit runs formatting/linting/type-checks automatically,
and git push also runs the test suite -- mirroring a typical Nest project's
husky + lint-staged setup. Projects scaffolded with austial new get the same
.pre-commit-config.yaml out of the box.
Using the CLI
austial new scaffolds a brand-new project exactly like nest new:
uv run austial new my-app
cd my-app
uv sync
cp .env.example .env
uv run austial serve
New projects depend on the published
austialpackage from PyPI by default. If you're developing the framework itself, point new projects at your local checkout instead with--link:austial new my-app --link /path/to/austial-py-- this adds an editable[tool.uv.sources]entry souv syncresolvesaustialfrom your local checkout rather than PyPI.
austial generate (alias austial g) adds artifacts to an existing project,
patching src/app_module.py's imports/imports=[...] array automatically --
just like nest g:
uv run austial generate module cats # src/modules/cats/cats_module.py
uv run austial generate controller cats # src/modules/cats/cats_controller.py
uv run austial generate service cats # src/modules/cats/cats_service.py
uv run austial generate resource cats # module + full CRUD controller/service/dto/entity
uv run austial g resource cats # same as above, short alias
Repository layout
austial-py/
├── pyproject.toml # package "austial", console-script entry point
├── LICENSE # MIT
├── assets/ # logo.svg (+ logo-dark.svg for dark mode) / icon.svg / apple-icon.png
├── austial/ # the framework (installable library) -- this *is* the package
│ ├── common/ # decorators, guards, interceptors, pipes, filters,
│ │ # middleware, exceptions, logger
│ ├── core/ # metadata/reflector, DI container, router builder,
│ │ # AustialFactory / AustialApplication
│ ├── config/ # ConfigModule / ConfigService
│ ├── database/ # DatabaseModule (SQLAlchemy async)
│ ├── terminus/ # HealthCheckService + health indicators
│ ├── testing/ # Test.create_testing_module(...)
│ └── cli/ # `austial new` / `generate` / `serve` + templates
└── tests/ # tests for the framework itself -- no sample app needed;
├── unit/ # test modules/controllers are defined inline per test file
└── e2e/
There's deliberately no src/ here -- that's what austial new generates for
your project, kept out of the framework's own repo. Test files use Nest's
*.spec.ts naming convention (*_spec.py here); pyproject.toml's
[tool.pytest.ini_options] is configured to discover them.
Request lifecycle
Every route runs through the same pipeline Nest uses:
guards -> pipes -> interceptors (wrapping) -> handler -> exception filters
from austial import Controller, Get, UseGuards, UseInterceptors
from austial.common.interceptors import TransformInterceptor
from .api_key_guard import ApiKeyGuard
@Controller("cats")
class CatsController:
@Get(":id")
@UseGuards(ApiKeyGuard)
@UseInterceptors(TransformInterceptor())
async def find_one(self, id: int):
...
Note path params use Nest's :id syntax (translated to FastAPI's {id}
under the hood), so route strings read exactly like their Nest counterparts.
Releasing
Pushing a v*.*.* tag triggers .github/workflows/publish.yml,
which re-runs the lint/type-check/test gate, builds the sdist + wheel with
uv build, publishes them to PyPI via
trusted publishing (no API
token stored as a secret), and attaches the built artifacts to a GitHub
release:
# bump the version in pyproject.toml first, then:
git commit -am "Bump to vX.Y.Z"
git tag -a vX.Y.Z -m "vX.Y.Z - ..."
git push origin main
git push origin vX.Y.Z
One-time setup: on PyPI's
publishing settings
for the project, add austial-py's publish.yml workflow (environment
pypi) as a trusted publisher.
License
Metadata
Release files for austial 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| austial-0.2.0.tar.gz | 7.1 kB | With provenance | Details for austial-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| austial-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for austial-0.2.0-py3-none-any.whl |
Total release size: 14.7 kB
Release files / austial-0.2.0.tar.gz
| Download URL | austial-0.2.0.tar.gz |
|---|---|
| Size | 7.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1594713dd819ede970efc777776d81a0a50330bbbaa90eb9a08c9a849ac5b40a
|
|
BLAKE2b-256 checksum How to use checksums |
cbfeb66c1a8d9f1bf04efad07fc94fb037d7df4e3c02845954ea4aa85b2c20b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 4, 2026.
Transparency logRelease files / austial-0.2.0-py3-none-any.whl
| Download URL | austial-0.2.0-py3-none-any.whl |
|---|---|
| Size | 7.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
518ae6f50faed9db1a9eb2b1db73fb041530a8e59dc1f162760721c8c72366f2
|
|
BLAKE2b-256 checksum How to use checksums |
c70d679e7d3d16b22f02d054c26d27af873b02dda6b24ffc3756ff82d251aef2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 4, 2026.
Transparency logSecurity for austial 0.2.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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for austial-0.2.0.tar.gz
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 Nov 4, 2026.
Transparency logA 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.