Projects

ProjectTemplates · 2026

FastAPI Boilerplate

A structured FastAPI starter with Poetry, Docker Compose, consistent response conventions and optional LangChain helpers. The layout I stopped rewriting.

  • Python
  • FastAPI
  • Poetry
  • Docker
  • LangChain
 poetry installInstalling dependencies from lock file poetry run uvicorn app.main:app --port 8000 --reloadINFO:     Uvicorn running on http://0.0.0.0:8000INFO:     Application startup complete. curl -s localhost:8000/openapi.json | jq -r .info.titleFastAPI

Templates · Project

Chapter
Templates and infrastructure
Year
Availability
Open source
Last commit

FastAPI Boilerplate is the project layout I stopped rewriting. It is a minimal starter with Poetry, Docker Compose, and directories already carved out for routers, middleware, models, dependencies and database wiring. I scaffolded it for a quiz-master AI backend and then kept reaching for it on the next thing.

Starting a Python API means remaking decisions I had already made. Where do routers live, how is config loaded, what shape does a response body have, does it run in Docker. None of those are interesting to redo, and getting them slightly different in every service is worse than getting them wrong the same way everywhere.

The response envelope

This is the piece I care about most. app/models/response.py defines a ResponseModel with six fields: status_code, message, data, error_code, timestamp and success. Its create_response classmethod stamps the timestamp itself, so no handler assembles metadata by hand. app/utils/create_response.py is a thin function over that classmethod, which is what routes actually import. A client then parses one shape across every endpoint, failures included, where success is false and error_code carries the reason. Six fields is small enough that nobody argues about the seventh.

The tree it gives

app/ holds core/ for config, db/ for database wiring, plus routers/, middlewares/, models/, internal/ and a dependencies.py. Most of those are empty by design. The template names a place for each concern rather than filling it with a domain it does not have. app/main.py is four lines and creates the FastAPI application, nothing more. The part that carries code is utils/, which sits outside app/. It holds a setup_logger that formats with file and line number, a LangChain initialiser for Ollama, and Ollama helpers for chat, embeddings and model management. Poetry pins Python 3.12, Pydantic v2 and Uvicorn.

Choices and their cost

  • One response envelope, used everywhere. A client parses a single shape, and no route rebuilds the metadata. The cost is that a handler returning a raw model bypasses the convention silently, because nothing enforces it.
  • Directories are carved out and left empty. A new service inherits a place for every concern without inheriting someone else’s domain. The cost is real: app/core/config.py is a blank file, so settings loading is still the first thing every project writes.
  • The AI helpers live in utils/, outside the app tree, so a plain CRUD service never imports them. Installing is another matter. torch, ollama, langchain and openai are main dependencies rather than an optional extras group, so poetry install pulls PyTorch for an API that will never touch it. Moving them behind a Poetry extra is the change I would make first.
  • It stays small deliberately. I extend it per project instead of growing the template, because a template that grows turns into a framework nobody reads.

Starting from it

poetry install
poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
curl -s localhost:8000/openapi.json | jq -r '.info.title'

The API answers on port 8000 with an empty OpenAPI document, because routers/ starts out with nothing in it. The first real edit is a router module included from app/main.py, whose handlers return through the envelope:

from app.utils.create_response import create_response

@router.get("/health")
def health():
    return create_response(status_code=200, message="ok", data={"status": "healthy"})

Rough edges and status

The Docker path does not work as written. docker-compose.yaml builds from a Dockerfile that is not in the repository, and its command points at app.main.main:app rather than app.main:app. tests/ exists with pytest declared as a dev dependency and no test files inside it yet. The Poetry path is the one I use and the one that works. It is open source under MIT, and I keep it as a starting point rather than a maintained product.

Next projectAgentic AI

Conversational Voice Agents

View project