Introduction
Austial is a production-ready web framework for Python, built on top of FastAPI and inspired by NestJS. It gives Python 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 generate artifacts.
FastAPI is a fantastic ASGI toolkit, but it doesn’t prescribe an application architecture. Austial is opinionated on top of FastAPI: modules own controllers and providers, providers get dependency-injected by type, and the request pipeline
guards -> pipes -> interceptors (wrapping) -> handler -> exception filtersis a first-class concept instead of something you hand-roll with
Depends() everywhere.

Why Austial#
Routing, guards, and interceptors are all declared with decorators that read top to bottom, in the order they execute:
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):
...Path params use a familiar :id syntax (translated to FastAPI’s {id}
under the hood), so route strings stay short, and the decorator stack —
guard, interceptor, handler — reads top to bottom in the order it executes.
Architecture at a glance#
- Modules —
@Module(imports=, controllers=, providers=, exports=)compose the application graph. - Controllers —
@Controller(prefix)plus@Get/@Post/@Put/@Patch/@Delete/@Options/@Headdeclare routes. - Providers —
@Injectable(scope=Scope.DEFAULT | Scope.TRANSIENT | Scope.REQUEST); the container resolves__init__type hints recursively, singleton by default. Custom providers use provider dicts:{"provide": TOKEN, "useClass"/"useValue"/"useFactory"/"useExisting": ..., "inject": [...]}.ModuleRef,DiscoveryService,LazyModuleLoaderandforward_refcover runtime lookup and circular graphs. - Bootstrap —
AustialFactory.create(AppModule)returns anAustialApplication;await app.listen(8000)starts it.AustialFactory.create_application_context(AppModule)builds the graph without HTTP. Providers can hookon_module_init…on_application_shutdown. - Guards —
CanActivateABC +ExecutionContext, applied with@UseGuards(...). - Interceptors —
NestInterceptorABC (intercept(context, call_next)), applied with@UseInterceptors(...). - Pipes —
PipeTransformABC, includingValidationPipe, theParse*Pipefamily,DefaultValuePipeandParseFilePipe. - Exception filters —
ExceptionFilterABC +@Catch(...), with a defaultAllExceptionsFilter. - Middleware —
NestMiddlewareABC, wired up viaconfigure(consumer)on modules. - Config —
ConfigModule.for_root(env_file=".env")/ConfigService. - Database —
austial.orm, a from-scratch TypeORM-shaped ORM:@Entity(),Repository,QueryBuilder, wired up viaOrmModule.for_root(...). - More building blocks —
austial.websockets(gateways, rooms),austial.microservices(TCP/local transports, hybrid apps),austial.cqrs,austial.schedule(@Cron/@Interval/@Timeoutand a runtime registry),austial.http(an injectable HTTP client),austial.openapi,austial.graphql(Strawberry),austial.mongo,austial.prisma, OAuth/OIDC social login inaustial.auth, and@Rendertemplates. - Cross-cutting techniques —
austial.cache(CacheModule,CacheInterceptor,@CacheKey/@CacheTTL),austial.events(EventEmitter,@OnEventwith wildcards), a pluggableLogger/LoggerService, globalAPP_GUARD/APP_PIPE/APP_INTERCEPTOR/APP_FILTERproviders, async providers, and testing overrides. - HTTP extras — API versioning, a global prefix, host routing,
@Redirect,@Sse,StreamableFile, file-upload helpers, response serialization (@Exclude/@Expose) and mapped types (PartialType, …). - Health checks —
austial.terminus.HealthCheckService+MemoryHealthIndicator,DatabaseHealthIndicator. - Testing —
austial.testing.Test.create_testing_module(...).compile(). - CLI —
austial new <name>/austial generate|g module|controller|service|resource <name>.
A note on file names#
Some JavaScript frameworks name 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 is one folder per feature under src/app/modules/, next to the root module in src/app/, with shared code in
src/shared/ and non-Python assets in src/templates/.
What’s not (yet) implemented#
Austial is deliberately opinionated but not a 1:1 port of any single framework. A few concepts are intentionally out of scope for now, so you don’t go looking for them:
- Module visibility is opt-in — by default every module’s providers live in one
flat, application-wide container;
strict_modules=Trueenforcesimports/exports(see Module Visibility). - Pluggable HTTP platform — Austial runs on FastAPI/Starlette only; there is no Express-or-Fastify-style adapter layer.
- GraphQL beyond Strawberry — code-first schemas via Strawberry only; no schema-first mode or federation helpers (subscriptions work over WebSocket).
- SQL ORMs beyond the built-in one — it supports PostgreSQL and SQLite; there is no TypeORM, Sequelize or MikroORM adapter. MongoDB has Mongoose-style models; Prisma is wired in at the connection level.
- RxJS-style interceptor streams —
CallHandler.handle()is a plain async continuation, not an Observable.
None of this blocks building a real API with the full request lifecycle — it’s just worth knowing up front.