Litestar (formerly Starlite) is an ASGI framework that's earned a reputation as a serious FastAPI alternative — it's fast, has first-class dependency injection, built-in DTOs, and excellent typing. Deploying it is similar to any ASGI app but with a few framework-specific touches. This guide covers a production deployment with a managed database.
Litestar vs FastAPI in production
Both are ASGI frameworks, so the deployment shape is identical: an ASGI app served by an ASGI server (Uvicorn or Granian) behind an ingress. The differences that matter for production:
- Litestar has built-in plugins for SQLAlchemy, so DB session lifecycle is handled by the framework.
- It ships structured DI and lifecycle hooks (
on_startup,on_shutdown) you'll use for DB pools. - Its
create_appfactory pattern is the recommended entry point.
A minimal app
# app/main.py
from litestar import Litestar, get
@get("/")
async def index() -> dict[str, str]:
return {"message": "Hello from Litestar"}
@get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
app = Litestar([index, health])Choosing an ASGI server
Uvicorn is the default. For production you run it with multiple workers or behind Gunicorn. Granian (a Rust-based server) is an increasingly popular alternative with strong performance. We'll use Uvicorn for familiarity:
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4The --host 0.0.0.0 is mandatory in a container, and the port should come from the injected PORT env var.
Database integration with the SQLAlchemy plugin
Litestar's SQLAlchemyPlugin (via advanced-alchemy) wires async SQLAlchemy into the app and manages session scoping per request:
# app/main.py
from litestar import Litestar, get
from litestar.plugins.sqlalchemy import SQLAlchemyPlugin, SQLAlchemyAsyncConfig
import os
db_config = SQLAlchemyAsyncConfig(
connection_string=os.environ["DATABASE_URL"].replace(
"postgres://", "postgresql+asyncpg://", 1
),
create_all=False, # use migrations, not create_all, in prod
)
@get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
app = Litestar(
route_handlers=[health],
plugins=[SQLAlchemyPlugin(db_config)],
)Note the scheme rewrite: managed Postgres gives you postgres://, but async SQLAlchemy needs postgresql+asyncpg://. Doing the replacement at startup avoids confusing connection errors.
With a managed PostgreSQL database linked, DATABASE_URL is injected automatically.
Migrations with Alembic
Litestar + advanced-alchemy integrates with Alembic. Initialize and run migrations as a release step:
alembic upgrade headNever set create_all=True in production — it doesn't handle schema evolution. Use Alembic and run alembic upgrade head once per release, before traffic shifts to the new version.
The Dockerfile
FROM python:3.12-slim AS base
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /app
# Install uv for fast, reproducible installs
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev
COPY . .
ENV PATH="/app/.venv/bin:$PATH"
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]Using uv with a frozen lockfile makes installs fast and reproducible — a meaningful build-time win over plain pip. If you prefer pip, swap in requirements.txt and pip install --no-cache-dir -r requirements.txt.
Worker count tuning
For CPU-bound work, set workers to roughly (2 × cores) + 1. But on a platform with small container tiers, fewer workers with more async concurrency is often better — async frameworks like Litestar handle many concurrent requests per worker. Start with 2 workers on a small tier and scale up the tier or replica count under load rather than cramming workers into a tiny container.
Environment variables
| Variable | Purpose |
|---|---|
DATABASE_URL | injected by managed DB link |
PORT | bind port (use in CMD) |
LITESTAR_DEBUG | 0 in production |
WEB_CONCURRENCY | worker count |
Make your CMD read PORT: use a shell form like sh -c 'uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-8000} --workers ${WEB_CONCURRENCY:-2}'.
Graceful shutdown
Litestar's on_shutdown lifecycle hooks let you close DB pools cleanly. The SQLAlchemy plugin handles its own teardown, but if you open other resources (Redis, HTTP clients), register shutdown handlers so in-flight requests finish during a rolling deploy.
Deploying
Push the repo, connect it, link a managed PostgreSQL database, set env vars, and add the alembic upgrade head release step. The platform builds the Dockerfile (or auto-detects Python via buildpacks) and deploys. Live logs show Uvicorn booting and any asyncpg connection issues.
git push origin mainConclusion
Litestar deploys like any well-built ASGI app: Uvicorn binding to 0.0.0.0 and the injected port, the SQLAlchemy plugin for DB lifecycle, Alembic migrations as a release step, and the postgres:// to postgresql+asyncpg:// rewrite. Its built-in DI and DTOs make the application code cleaner than the FastAPI equivalent.
Try Litestar plus a managed PostgreSQL on PandaStack's free tier — connect your repo at [dashboard.pandastack.io](https://dashboard.pandastack.io) and the database wires itself in automatically.
References
- [Litestar Documentation](https://docs.litestar.dev/)
- [Litestar SQLAlchemy Plugin / Advanced Alchemy](https://docs.advanced-alchemy.litestar.dev/)
- [Uvicorn: Deployment](https://www.uvicorn.org/deployment/)
- [Alembic Documentation](https://alembic.sqlalchemy.org/)
- [uv: Python Package Manager](https://docs.astral.sh/uv/)