How Litestar and FastAPI compare on scope, dependency injection, serialization, class-based controllers and governance, with the same endpoint written in each.
Litestar and FastAPI are both async, type-driven Python API frameworks that generate OpenAPI docs from your annotations. FastAPI is the better known of the two, with a large ecosystem and a single original author. Litestar ships more features in the core and is run by a team of maintainers. The overlap is large enough that the decision usually comes down to scope and governance rather than syntax.
The main differences:
Provide at any layer of the app, while FastAPI declares them with Depends in the handler signature.The Litestar documentation describes it as not a microframework and lists ORM integration, sessions, caching and OpenTelemetry support among the built-in features. It also notes the project is community-driven with a core team of maintainers. The signup endpoint, with a pool opened in a startup hook:
import os
from dataclasses import dataclass
import asyncpg
from litestar import Litestar, post
from litestar.datastructures import State
@dataclass
class Signup:
email: str
async def open_pool(app: Litestar) -> None:
app.state.pool = await asyncpg.create_pool(os.environ["DATABASE_URL"])
async def close_pool(app: Litestar) -> None:
await app.state.pool.close()
@post("/users")
async def create_user(data: Signup, state: State) -> dict[str, str]:
await state.pool.execute("INSERT INTO users (email) VALUES ($1)", data.email)
return {"email": data.email}
app = Litestar(
route_handlers=[create_user], on_startup=[open_pool], on_shutdown=[close_pool]
)
The request body arrives as data, and a plain dataclass is enough to validate it. Serialization goes through msgspec, a separate library focused on fast JSON encoding and validation. Litestar's dependency injection lets you register a provider once on the app or a controller instead of repeating it per handler.
FastAPI builds on Starlette for the web layer and Pydantic for data. In the 2024 Python Developers Survey run by the Python Software Foundation and JetBrains, 38% of respondents used FastAPI, up from 21% in 2021. Litestar was not among the frameworks listed separately. FastAPI dependencies are declared with Depends in each handler signature, and they can be nested and shared through routers.
import os
from contextlib import asynccontextmanager
import asyncpg
from fastapi import FastAPI, Request
from pydantic import BaseModel
class Signup(BaseModel):
email: str
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.pool = await asyncpg.create_pool(os.environ["DATABASE_URL"])
yield
await app.state.pool.close()
app = FastAPI(lifespan=lifespan)
@app.post("/users", status_code=201)
async def create_user(req: Signup, request: Request) -> dict:
await request.app.state.pool.execute(
"INSERT INTO users (email) VALUES ($1)", req.email
)
return {"email": req.email}
FastAPI's strength is the number of people who already know it. Most Python developers have seen a FastAPI app, and the volume of public FastAPI code means coding agents have many examples to follow.
Encore combines the framework you chose with infrastructure declared in Python. The infrastructure SDK is the encore-dev package, and Litestar or FastAPI keeps routing and request handling. Postgres databases, Pub/Sub topics, object storage buckets, cron jobs and secrets are module-level declarations that Encore discovers and provisions.
In Litestar, encore.start goes in on_startup, and the handler uses the declared database directly instead of a pool on State:
import encore
from encore.storage import postgres
from litestar import Litestar, post
from pydantic import BaseModel
db = postgres.Database("users", migrations="./migrations")
class Signup(BaseModel):
email: str
@post("/users")
async def create_user(data: Signup) -> dict[str, str]:
await db.exec("INSERT INTO users (email) VALUES ($1)", data.email)
return {"email": data.email}
app = Litestar(route_handlers=[create_user], on_startup=[encore.start])
In FastAPI, the same db declaration works, and await encore.start() goes in the lifespan function.
encore run starts Postgres locally and applies the migrations, along with any topics and buckets, and the CLI reference covers encore test for tests that get their own database.
A deploy provisions the same declarations in your own AWS or GCP account.
Cloud access sits with Encore's IAM role, not the agent, so an agent adding a topic to a Litestar controller writes a declaration rather than cloud configuration. The AI integration guide covers how to give an agent these conventions.
Python support is in beta, and you can request access.
Encore works with either when you want databases and queues running locally and provisioned in your own cloud account.
FastAPI is the more common choice when you want the largest ecosystem and the widest familiarity among developers and AI coding agents. Litestar fits teams that want more built in, such as class-based controllers and DTOs, and that prefer a framework run by a team of maintainers.
Litestar uses msgspec for serialization by default, which often makes it faster in serialization-heavy benchmarks. For most APIs the database and network calls dominate response time, so the difference rarely decides the choice.
Yes. Litestar accepts Pydantic models, dataclasses, TypedDicts and msgspec Structs for request and response data.
Install the encore-dev package, declare postgres.Database at module scope and pass encore.start to on_startup. Handlers call db.exec and db.query directly. encore run starts Postgres locally, and a deploy provisions the database in your own AWS or GCP account.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.