FastAPI Layered Architecture Project Structure
Clean Architecture with domain, application, and infrastructure layers. Dependency inversion for testability.
Project Directory
myproject/
main.py
Composition root
src/
Source code
__init__.py
domain/
Business logic, no dependencies
__init__.py
entities/
__init__.py
user.py
Domain entity
order.py
value_objects/
__init__.py
email.py
money.py
repositories/
Abstract interfaces
__init__.py
user_repository.py
ABC
order_repository.py
services/
Domain services
__init__.py
pricing_service.py
application/
Use cases, orchestration
__init__.py
use_cases/
__init__.py
create_user.py
place_order.py
get_user.py
dto/
Data transfer objects
__init__.py
user_dto.py
order_dto.py
infrastructure/
External concerns
__init__.py
persistence/
Database implementations
__init__.py
database.py
models.py
SQLAlchemy
user_repository_impl.py
Concrete impl
order_repository_impl.py
external/
Third-party services
__init__.py
email_service.py
payment_gateway.py
api/
HTTP layer
__init__.py
dependencies.py
DI wiring
v1/
__init__.py
router.py
users.py
orders.py
schemas/
Pydantic request/response
__init__.py
user.py
order.py
tests/
__init__.py
conftest.py
unit/
Domain/application tests
__init__.py
test_entities.py
test_use_cases.py
integration/
__init__.py
test_repositories.py
test_api.py
requirements.txt
requirements-dev.txt
.env.example
.gitignore
pyproject.toml
Why This Structure?
This structure enforces the Dependency Rule: inner layers know nothing about outer layers. Domain contains pure business logic with zero imports from infrastructure. Use cases orchestrate domain objects. Infrastructure implements interfaces defined in domain.
Key Directories
- src/domain/-Entities, value objects, repository interfaces—no deps
- src/application/-Use cases that orchestrate domain logic
- src/infrastructure/-Database, external APIs—implements domain interfaces
- src/api/-HTTP routes, Pydantic schemas, DI wiring
Getting Started
python -m venv venv && source venv/bin/activatepip install -r requirements.txtcp .env.example .envuvicorn main:app --reload
Dependency Rule
- Domain-No imports from other layers
- Application-Imports only from domain
- Infrastructure-Imports from domain and application
- API-Imports from all layers, wires DI
Repository Pattern
# src/domain/repositories/user_repository.py
from abc import ABC, abstractmethod
class UserRepository(ABC):
@abstractmethod
async def get_by_id(self, id: int) -> User | None: ...
# src/infrastructure/persistence/user_repository_impl.py
class SQLAlchemyUserRepository(UserRepository):
async def get_by_id(self, id: int) -> User | None:
# actual DB query here
When To Use This
- Complex domains with significant business logic
- Projects requiring high testability
- Teams familiar with DDD concepts
- Long-lived applications expecting evolution
- When you need to swap infrastructure easily
Trade-offs
- More boilerplate-Interfaces, DTOs, mapping between layers
- Learning curve-Team needs to understand layer boundaries
- Overkill for CRUD-Simple apps don't benefit from this complexity
Testing Strategy
- tests/unit/-Test domain and use cases with mock repos
- tests/integration/-Test repos against real DB, API e2e
- Domain isolation-Unit tests need zero infrastructure