An open-source, production-oriented FastAPI service template inspired by Ardan Labs Service.
The project translates Ardan's emphasis on explicit boundaries, small mental models, operational completeness, and domain-oriented design into idiomatic Python. It is intended to be a starting point, not another framework layered on top of FastAPI.
Project status: early scaffold with a working runtime and operations baseline. The reference business domain and template-generation experience are still in progress; roadmap items are checked only when the corresponding repository artifacts and validation exist.
- Why this project exists
- Design principles
- Target architecture
- Pydantic's role
- Planned capabilities
- Repository status
- Getting started
- Validation
- Delivery roadmap
- Domain scaffolding contract
- Contributing
- License
- Acknowledgments
Many FastAPI examples demonstrate routing and database access but stop before the concerns that make a service maintainable in production. This template aims to provide a coherent reference for:
- keeping business rules independent of FastAPI and persistence;
- organizing a modular service around domain language;
- defining explicit transaction and dependency boundaries;
- testing domain behavior without HTTP, PostgreSQL, or network access;
- shipping local and Kubernetes workflows from the same repository;
- providing logs, metrics, traces, health signals, security, and CI by default;
- generating new domain seams without generating business rules.
The initial reference domain will model inventory and catalog management. A separate identity capability will demonstrate local account signup, user management, RBAC, and a replaceable external OIDC adapter.
- Pragmatic DDD — use entities, value objects, aggregates, and domain events only when they clarify real business rules.
- Dependencies point inward — domain code has no FastAPI, Pydantic, SQLAlchemy, or infrastructure imports.
- Frameworks stay at the edges — FastAPI is the HTTP adapter, not the application architecture.
- Explicit mapping — transport schemas, domain models, and persistence models evolve independently.
- Use-case transactions — the application layer owns commit and rollback; repositories never commit independently.
- Operations are architecture — containers, Kubernetes, migrations, telemetry, and CI are maintained alongside the service.
- Minimal dependencies — add libraries for demonstrated needs, not for hypothetical flexibility.
The architecture is easiest to read as four focused views rather than one dense diagram:
See the editable source at
docs/architecture-context.mmd.
See the editable source at
docs/architecture.mmd.
See the editable source at
docs/request-lifecycle.mmd.
See the editable source at
docs/deployment-flow.mmd.
The composition root is the only place that knows every concrete adapter. Domain modules are mirrored across layers so a feature remains traceable from HTTP input to business behavior and storage.
The current repository shape is:
ddd-fast-api/
├── .github/workflows/ # Quality, security, and delivery checks
├── .husky/ # Local commit hooks
├── alembic/ # Database migrations
├── docs/ # ADRs, architecture, diagrams, and validation
├── src/ddd_fast_api/
│ ├── entrypoints/http/ # FastAPI routes, schemas, dependencies, telemetry
│ ├── application/ # Catalog and identity use cases
│ ├── domain/ # Catalog and identity entities, rules, and ports
│ ├── infrastructure/
│ │ ├── persistence/ # SQLAlchemy models, mappers, repositories, UoW
│ │ └── http_client.py # Timeout and bounded-retry HTTP adapter
│ ├── foundation/ # Settings, errors, logging, auth, telemetry
│ └── bootstrap.py # Composition root and application lifecycle
├── tests/
│ ├── unit/
│ ├── integration/
│ └── architecture/
├── zarf/ # Compose, Helm, Kustomize, and Kind assets
├── main.py # Compatibility application entrypoint
├── package.json # Husky setup
├── pyproject.toml
├── uv.lock
└── Makefile
Pydantic will validate and serialize data at system boundaries:
- API request and response schemas;
- OpenAPI generation;
- application configuration through
pydantic-settings; - messages exchanged with external systems.
Core domain entities and value objects remain plain Python types or dataclasses. Explicit mappers translate between Pydantic schemas, domain models, and SQLAlchemy models. This separation keeps business behavior testable and allows the HTTP, domain, and persistence representations to evolve independently.
The template targets Python equivalents for the production capabilities shown by Ardan Labs Service:
- FastAPI and Starlette routing, lifespan, dependencies, and middleware;
- PostgreSQL with SQLAlchemy 2 async, asyncpg, and Alembic;
- CRUD use cases, filtering, ordering, pagination, and stable errors;
- local accounts, JWT/OIDC authentication, RBAC, and object-level policies;
- structured logging, OpenTelemetry, Prometheus-compatible metrics, Tempo, and Grafana;
- pytest-based unit, integration, contract, property, architecture, and smoke tests;
- locked dependencies with an optional wheelhouse for offline builds;
- multi-stage Docker images and Docker Compose for local development;
- Helm/Kustomize-based Kubernetes environments, a local Kind registry workflow, and a separate migration Job;
- GitHub Actions as the default CI/CD implementation, with CircleCI documented as an alternative;
- OpenAPI, MkDocs, and source-reference documentation;
- a project template and domain-scaffolding command.
A capability counts as implemented only when code or configuration, automated tests, user documentation, and a passing CI check all exist.
Currently present:
- Git repository and
mainbranch; - Python project metadata, runtime dependencies, and development tooling baseline;
- a uv lockfile for the current executable scaffold;
- Python 3.12+ support decision;
- typed runtime settings with an
.env.examplebootstrap; - a foundation error model and FastAPI exception handler registration;
- structured JSON logging wired into the bootstrap path;
- SQLAlchemy async and Alembic persistence scaffolding;
- a SQLAlchemy catalog ORM model and repository adapter scaffold;
- a SQLAlchemy-backed catalog unit-of-work seam for application-owned catalog transaction boundaries;
- an initial Alembic revision for the catalog table;
- bootstrap-managed shared persistence resources for the SQLAlchemy path;
src/ddd_fast_apilayer packages for entrypoints, application, domain, infrastructure, and foundation;- the first plain-Python catalog domain skeleton with invariant tests;
- the first plain-Python identity domain skeleton with invariant tests;
- the first identity repository port and application lookup use case;
- a sample identity HTTP endpoint with structured 400/404 responses;
- a SQLAlchemy identity ORM model and repository adapter scaffold;
- the first application-layer catalog use case and repository port;
- a sample catalog HTTP endpoint wired through the application layer;
- catalog list filtering, ordering, and pagination through typed domain and HTTP query models;
- a sample catalog detail endpoint with structured 400/404 responses;
- a settings-driven seam for choosing the catalog adapter (defaulting to memory);
- a settings-driven seam for choosing the identity adapter (defaulting to memory);
- an initial architecture test that guards domain-layer imports;
- expanded architecture tests that guard domain, application, and foundation layer boundaries;
- a minimal FastAPI app factory with
/and/healthroutes; - replaceable bearer authentication and permission dependency examples;
- liveness, readiness, startup, request telemetry, and Prometheus metrics routes;
- a shared timeout- and bounded-retry outbound HTTP adapter;
- an initial unit test covering the scaffold entrypoints;
- a GitHub Actions quality workflow definition for tests, Ruff, and mypy;
- optional Husky git hooks for commit-time formatting, linting, and conventional commit validation;
- explicit Pydantic boundary schemas for the scaffold metadata endpoints;
- repository ignore rules;
- this project overview;
- MIT licensing.
Not yet present:
- business-domain implementation beyond the scaffold metadata endpoints;
- contract and smoke test layers.
The repository contains an executable foundation and production-runtime baseline. You can install the dependencies, prepare the environment file, run the app, and inspect the package layout that future domain work will build on:
git clone https://github.com/owezzy/ddd-fast-api.git
cd ddd-fast-api
uv sync --group dev
cp .env.example .env
uv run python main.pyThe local server starts on http://127.0.0.1:8000 and currently exposes:
GET /— scaffold metadataGET /health— simple health checkGET /catalog/items— sample catalog items via the application layer with optional filtering, ordering, and pagination query parametersGET /catalog/items/{sku}— one sample catalog item by SKUGET /identity/users/{email}— one sample user account by email
Current runtime configuration lives in src/ddd_fast_api/foundation/settings.py
and is populated from .env using the DDD_FAST_API_ prefix.
The catalog endpoints currently default to the in-memory adapter. The SQLAlchemy
adapter can be selected by setting DDD_FAST_API_CATALOG_REPOSITORY_BACKEND
to sqlalchemy. When selected, the app now reuses bootstrap-managed persistence
resources for the default configuration and falls back to an isolated engine in
override-driven tests. Catalog application use cases now execute through an
explicit catalog unit-of-work seam instead of depending directly on raw
repository instances.
If you prefer stable task-style commands over raw uv invocations, the current scaffold also provides:
make sync
make run
make test
make lint
make type-checkOptional contributor git tooling is also available:
make hooks
make commitmake hooksinstalls the local Husky git hooks frompackage.jsonand configures Git to use the Commitizen dialog for manualgit commitcommands.- The
pre-commithook runsmake formatandmake lintbefore each commit. - The
commit-msghook validates messages with Commitizen's conventional commit rules. make commitopens an interactive Commitizen prompt viauv run cz commit.
Read these sections next:
- Design principles for the rules every contribution must preserve.
- Target architecture for layer responsibilities and dependency direction.
- Pydantic's role for the boundary-versus-domain decision.
- Repository status for an accurate implementation snapshot.
- Delivery roadmap for the planned build sequence.
Runtime capability details are documented in
docs/production-runtime.md.
Development requirements for the current scaffold are:
- Git
- Python 3.12+
- uv
Optional local commit-hook workflow requirements:
- Node.js
- npm
CI tests Python 3.12, 3.13, and 3.14. Docker, Docker Compose, Kind, kubectl, Helm, and Kustomize are requirements for the operations workflows.
The root main.py is now a compatibility bootstrap that starts the packaged
application. It exists to keep the first runnable command simple while the
project transitions fully into the src/ddd_fast_api layout.
The end-to-end validation path is documented in
docs/validation.md. It covers fresh-clone quality
checks, live application smoke checks, Compose database startup, and Helm and
Kustomize rendering. The CI delivery job runs configuration and packaging
checks automatically; Docker, Kind, and live HTTP checks are run locally when
those tools are available.
- Define architecture, feature parity, and dependency rules.
- Initialize and publish the repository.
- Establish Python 3.12+ and MIT license decisions.
- Foundation: package layout, configuration, lifecycle, errors, logging, dependency rules, quality tools, and architecture tests.
- Reference slice: inventory/catalog contract, domain behavior, PostgreSQL adapter, migrations, and tests.
- Production runtime: account management, authentication, authorization, telemetry, health checks, and resilient HTTP clients.
- Operations: Docker, Compose, migration jobs, Helm/Kustomize Kubernetes packaging, CI/CD, and security scanning.
- Template experience: project generation, domain scaffolding, documentation, examples, and releases.
- Validation: validate a fresh clone, run the documented workflows, deploy to local and Kubernetes environments, and complete a newcomer review.
See CONTRIBUTING.md for the current contributor workflow, local quality gates, and commit conventions.
The intended domain generator contract is documented in
docs/scaffolding.md so future implementation work has a
stable architectural target.
Architecture decisions that are expensive to reverse, surprising without
context, and based on a real trade-off should be recorded under
docs/adr/.
Distributed under the MIT License.
- Ardan Labs Service for the production service architecture and operational-completeness inspiration.
- FastAPI and Pydantic for Python's typed API boundary tools.
- Architecture Patterns with Python by Harry Percival and Bob Gregory for practical ports, adapters, repositories, and units of work in Python.