( Comparison )

Austial vs FastAPI: when structure pays off

This is not a choice between two rivals. Austial runs on FastAPI and keeps its routing, Pydantic models and OpenAPI docs. The question is whether your project benefits from the extra structure Austial adds on top.

Side by side

Side by side
TopicFastAPIAustial
ArchitectureUnopinionated, you choose the layoutModules own controllers and providers, one folder per feature
Dependency injectionDepends() wired at each routeConstructor injection resolved from type hints
Request lifecycleMiddleware and dependencies you composeGuards, pipes, interceptors and exception filters in a fixed order
RoutingDecorators on an app or router@Controller with @Get and @Post, and :id path parameters
Error shapeHTTPException and 422 validation errorsOne consistent JSON error shape through exception filters
DatabaseBring your own libraryaustial.orm with repositories and Alembic migrations
Project setupYour own scaffoldingaustial new, generate and serve
TestingTestClient or httpx against your appA testing module with a real DI graph

When Austial is a good fit

  • A backend that will grow across many features and several contributors.
  • Teams that want one agreed way to structure modules, services and cross-cutting concerns.
  • Services that need authentication, tenancy, security defaults and background jobs from day one.
  • Developers coming from NestJS who want the same structure in Python.

When plain FastAPI is enough

A small service, a prototype, a script with a few endpoints or a single-file API does not need modules and a request pipeline. If you can hold the whole codebase in your head, FastAPI alone keeps things lighter.

The trade-offs

Austial is opinionated, and it is not FastAPI, Django or NestJS, so you learn its API instead of assuming one. A few concepts are out of scope for now: request-scoped providers, enforced module visibility and RxJS-style interceptor streams.

The same endpoint, both ways

Here is a read endpoint that needs a service. In FastAPI the dependency is wired at the route with Depends(). In Austial the controller declares what it needs in its constructor, and the module registers the provider once.

# FastAPI
from fastapi import Depends, FastAPI

app = FastAPI()


def get_cats_service() -> CatsService:
    return CatsService()


@app.get("/cats/{id}")
async def find_one(id: int, service: CatsService = Depends(get_cats_service)) -> Cat:
    return service.find_one(id)
Plain FastAPI

The Austial version

# Austial
from austial import Controller, Get, Module


@Controller("cats")
class CatsController:
    def __init__(self, service: CatsService):
        self.service = service

    @Get(":id")
    async def find_one(self, id: int) -> Cat:
        return self.service.find_one(id)


@Module(controllers=[CatsController], providers=[CatsService])
class CatsModule:
    pass
Austial, which compiles down to a FastAPI route

Frequently asked questions

Is Austial a replacement for FastAPI?

No. Austial is built on FastAPI. Your routes are real FastAPI routers and your request bodies are Pydantic models.

Will my FastAPI knowledge transfer?

Yes. Pydantic, type hints, async handlers and the OpenAPI docs work as you expect. What changes is how you organise code and wire dependencies.

Can I still see Swagger UI?

Yes. Scaffolded projects serve FastAPI's Swagger UI at /docs.

Go deeper in the docs

( Keep reading )

( Click. Copy. Build. )

Seeing “command not found”? Run uv tool update-shell, then open a new terminal. Details