A production-ready FastAPI template with PostgreSQL, Alembic migrations, dependency injection, and comprehensive testing setup.
- FastAPI - Modern, fast web framework for building APIs
- SQLAlchemy 2.0+ - Async ORM with PostgreSQL support
- Alembic - Database migration tool
- Dependency Injector - DI container for clean architecture
- Pydantic Settings - Environment-based configuration
- Loguru - Beautiful, intuitive logging with automatic rotation
- Transactional Support -
@transactionaldecorator for auto-commit/rollback - Database Instrumentation - Slow query logging and performance monitoring
- pytest + testcontainers - Comprehensive testing with isolated PostgreSQL
- UV Package Manager - Fast Python package management
- Type Safety - Full mypy type checking support
- Code Quality - Ruff for linting and formatting
app/
├── core/ # Core application modules
│ ├── config.py # Pydantic settings
│ ├── container.py # DI container
│ ├── exceptions.py # Custom exceptions
│ └── logs.py # Loguru logging configuration
├── database/ # Database layer
│ ├── connection.py # Database manager with instrumentation
│ ├── models.py # SQLAlchemy models
│ ├── base.py # Model imports for Alembic
│ ├── decorators.py # @transactional decorator
│ ├── instrumentation.py # Query logging & metrics
│ └── repositories/ # Data access layer
├── services/ # Business logic layer
│ ├── auth_service.py
│ └── user_service.py
└── routes/ # API routes
├── middleware/ # Auth and error handlers
├── schemas/ # Request/response schemas
└── v1/ # API version 1
alembic/ # Database migrations
tests/ # Test suite
├── conftest.py # Test fixtures
├── unit/ # Unit tests
└── integration/ # Integration tests
- Python 3.12+
- UV package manager (installation)
- Docker (for PostgreSQL)
-
Clone and setup
# Install dependencies uv sync --all-extras -
Start PostgreSQL
docker compose up -d
-
Configure environment
Option A: Using 1Password (recommended for teams)
# Install 1Password CLI: https://developer.1password.com/docs/cli/get-started/ op signin make env-fetchOption B: Manual setup
cp .env.example .env # Edit .env with your settings -
Run migrations
export DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app_db alembic upgrade head -
Start development server
uv run python -m app.main
Visit http://127.0.0.1:8000/docs for interactive API documentation.
The project includes a Makefile for common tasks:
make help # Show all available commands
make setup # Complete initial setup (install + docker + migrate)
make dev # Start development environment
make run # Start development server
make test # Run tests
make test-cov # Run tests with coverage
make quality # Run all code quality checks (format + lint + type-check)
make migrate # Run database migrations
make migrate-auto MSG="description" # Generate new migration
make docker-up # Start PostgreSQL
make docker-down # Stop PostgreSQL
make env-fetch # Fetch .env from 1Password
make env-push # Push .env to 1Password
make ci # Run CI checks (quality + tests)See full list: make help
# Production dependency
uv add <package-name>
# Development dependency
uv add --dev <package-name>CRITICAL: Alembic reads DATABASE_URL from environment variable, NOT from .env file!
Create new migration:
# MUST export DATABASE_URL first
export DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app_db
alembic revision --autogenerate -m "description"Apply migrations:
# MUST export DATABASE_URL first
export DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app_db
alembic upgrade headRollback migration:
export DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app_db
alembic downgrade -1Why? Alembic runs before the application starts, so it can't use the .env file. The DATABASE_URL environment variable must be set in your shell.
# Format code
uv run ruff format .
# Lint code
uv run ruff check --fix .
# Type checking
uv run mypy app/
# Run all checks
uv run ruff format . && uv run ruff check --fix . && uv run mypy app/# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=app
# Run specific test file
uv run pytest tests/integration/test_auth.py
# Run specific test
uv run pytest tests/integration/test_auth.py::test_get_me -vAll configuration is managed through environment variables in .env file.
Store your .env securely in 1Password:
# First time: push your .env to 1Password
make env-push
# Team members: fetch .env from 1Password
make env-fetchSee docs/1PASSWORD_SETUP.md for detailed setup.
| Variable | Description | Default |
|---|---|---|
APP_NAME |
Application name | FastAPI Bootstrap |
DEBUG |
Debug mode | false |
SERVER_HOST |
Server bind host | 0.0.0.0 (code default, .env.example uses 127.0.0.1) |
SERVER_PORT |
Server port | 8000 |
DATABASE_URL |
PostgreSQL connection URL | postgresql+asyncpg://... |
DATABASE_ECHO |
Echo SQL queries | false |
DATABASE_INSTRUMENTATION |
Enable query instrumentation | false |
CORS_ORIGINS |
Allowed CORS origins | localhost:3000,localhost:5173 |
AUTH_ENABLED |
Enable authentication | true |
FIREBASE_PROJECT_ID |
Firebase project ID | (empty) |
Visit http://127.0.0.1:8000/docs for interactive API documentation (Swagger UI).
GET /health- Health check with status and timestampGET /- Redirect to /docs
POST /api/v1/auth/sync- Sync authenticated user with databaseGET /api/v1/auth/me- Get current authenticated userPOST /api/v1/auth/logout- Logout current user
The application uses dependency-injector for clean separation of concerns:
- Container (app/core/container.py) - Wires dependencies
- Repositories - Data access layer
- Services - Business logic
- Routes - API controllers
- Models (app/database/models.py) - SQLAlchemy 2.0+ async models
- Repositories - Repository pattern for data access
- Migrations - Alembic for version control
- Transactional Decorator - Auto-commit/rollback for service methods:
from app.database.decorators import transactional class MyService: def __init__(self, session_factory): self._session_factory = session_factory @transactional async def create_item(self, data: dict, session: Optional[AsyncSession] = None): item = Item(**data) session.add(item) return item # Auto-commits when no session provided
- Instrumentation - Enable
DATABASE_INSTRUMENTATION=trueto log slow queries (>100ms warning, >1s error)
- Testcontainers - Isolated PostgreSQL for integration tests
- Fixtures - Reusable test data and mocked auth
- Coverage - Comprehensive test coverage tracking
The template uses Firebase as an example. To use a different auth provider:
- Update app/routes/middleware/auth.py
- Replace
verify_firebase_token()with your auth logic - Update environment variables in
.env
- Create model in app/database/models.py
- Import in base - Add to app/database/base.py for Alembic discovery
- Create repository in
app/database/repositories/ - Create service in
app/services/ - Wire in container - Add to app/core/container.py
- Create routes in
app/routes/ - Generate and apply migration:
make migrate-auto MSG="add entity_name" make migrate - Add tests in
tests/integration/
Build and run with Docker:
docker build -t fastapi-app .
docker run -p 8000:8000 --env-file .env fastapi-app- Set
SERVER_HOST=0.0.0.0for external access - Set
DEBUG=false - Use production database URL
- Configure CORS origins appropriately
- Use proper secrets management