A clean architecture starter template for FastAPI applications with PostgreSQL database, authentication, and proper project structure.
This project follows Clean Architecture principles with clear separation of concerns:
app/
βββ main.py # FastAPI application entry point
βββ api/ # API layer (routes, controllers)
β βββ deps.py # Dependency injection
β βββ v1/ # API version 1
β βββ auth_route.py # Authentication endpoints
β βββ division_route.py # Division management endpoints
β βββ user_route.py # User management endpoints
βββ core/ # Core application configuration
β βββ config.py # Application settings
β βββ security.py # Security utilities
βββ db/ # Database layer
β βββ base.py # Database base classes
β βββ session.py # Database session management
βββ models/ # Data models (SQLAlchemy)
β βββ user.py # User model
βββ repositories/ # Data access layer
β βββ division_repository.py
β βββ user_repository.py
βββ schemas/ # Pydantic schemas (DTOs)
β βββ division_schema.py
β βββ user_schema.py
βββ services/ # Business logic layer
β βββ division_service.py
β βββ user_service.py
βββ utils/ # Utility functions
βββ encryption.py
βββ http_error_response.py
- Clean Architecture: Proper separation of concerns with layers
- FastAPI: Modern, fast web framework for building APIs
- PostgreSQL: Robust relational database
- SQLAlchemy 2.0: Modern Python SQL toolkit and ORM
- Alembic: Database migration tool
- JWT Authentication: Secure authentication system
- Pydantic: Data validation using Python type annotations
- Docker: Containerized development environment
- pgAdmin: Database administration tool
- Python 3.9+
- Docker and Docker Compose
- Git
git clone <repository-url>
cd fastapi-clean-starterCreate a .env file in the root directory:
# Database
DATABASE_URL=postgresql://username:password@localhost:5432/db_name
# JWT Configuration
JWT_SECRET_KEY=your-super-secret-jwt-key-here
JWT_ALGORITHM=HS256
JWT_EXPIRATION_MINUTES=60
# Application
PROJECT_NAME=DTRAS APIdocker-compose up -d db pgadminpip install -r requirements.txtIf this is a fresh project setup and Alembic hasn't been initialized:
# Initialize Alembic (creates alembic/ directory and alembic.ini)
alembic init alembic
# Edit alembic.ini to set your database URL or use environment variable
# sqlalchemy.url = ???alembic upgrade headuvicorn app.main:app --reload --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000
Once the application is running, you can access:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc - OpenAPI JSON:
http://localhost:8000/openapi.json
This project uses Alembic for database migrations. The configuration is already set up in alembic.ini and alembic/env.py.
- Initialize Alembic (already done in this starter):
alembic init alembic- Configure Database URL in
alembic.ini:
# Option 1: Direct URL in alembic.ini
sqlalchemy.url = postgresql://username:password@localhost:5432/dbname
# Option 2: Use environment variable (recommended)
# sqlalchemy.url = - Configure env.py to use your models (already configured):
# In alembic/env.py
from app.db.base import Base # Import your Base
target_metadata = Base.metadataAuto-generate migration from model changes:
# Generate migration automatically by comparing models to database
alembic revision --autogenerate -m "Add user table"
# For more complex changes, create empty migration
alembic revision -m "Custom migration description"Best Practices for Migrations:
- Always review auto-generated migrations before applying
- Use descriptive migration messages
- Test migrations on a copy of production data
- Keep migrations small and focused
# Apply all pending migrations
alembic upgrade head
# Apply migrations up to a specific revision
alembic upgrade ae1027a6acf
# Apply only the next migration
alembic upgrade +1# Show current migration status
alembic current
# Show migration history
alembic history
# Show detailed history with descriptions
alembic history --verbose
# Show pending migrations
alembic show head# Rollback one migration
alembic downgrade -1
# Rollback to a specific revision
alembic downgrade ae1027a6acf
# Rollback all migrations (use with caution!)
alembic downgrade base# Create a branch
alembic revision --branch-label feature_branch -m "Feature branch migration"
# Merge branches
alembic merge -m "Merge feature branch" head1 head2
# Show branches
alembic branches- URL:
http://localhost:8080 - Email:
admin@admin.com - Password:
admin
Solution: Check if you're in the correct directory and the alembic version table exists:
# Stamp the database with current revision if version table is missing
alembic stamp headSolutions:
- Ensure models are properly imported in
alembic/env.py - Check that
target_metadatais set correctly - Verify database connection is working
Solution: Create a merge migration:
alembic merge -m "Merge conflicting revisions" revision1 revision2app/main.py: Application entry point with FastAPI instance and route registrationapp/api/: API layer containing route handlers and dependenciesapp/core/: Core application configuration and security utilitiesapp/db/: Database configuration and session managementapp/models/: SQLAlchemy ORM modelsapp/repositories/: Data access layer abstracting database operationsapp/schemas/: Pydantic models for request/response validationapp/services/: Business logic layer containing application use casesapp/utils/: Utility functions and helpers
- Model: Define database model in
app/models/ - Schema: Create Pydantic schemas in
app/schemas/ - Repository: Implement data access in
app/repositories/ - Service: Add business logic in
app/services/ - Route: Create API endpoints in
app/api/v1/ - Migration: Generate and apply migration with Alembic
Let's say you want to add a Product entity:
- Create the model (
app/models/product.py):
from sqlalchemy import Column, Integer, String, Numeric
from app.db.base import Base
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
price = Column(Numeric(10, 2), nullable=False)- Import in base.py (
app/db/base.py):
from app.models.product import Product # Add this import- Generate migration:
alembic revision --autogenerate -m "Add products table"
alembic upgrade head- Create schemas, repository, service, and routes following the existing patterns.
Follow these conventions:
- Use type hints for all function parameters and return types
- Follow PEP 8 style guidelines
- Use descriptive variable and function names
- Add docstrings to all public functions and classes
The application includes JWT-based authentication with the following endpoints:
POST /api/v1/auth/login- User loginPOST /api/v1/auth/register- User registrationGET /api/v1/auth/me- Get current user info
The application includes a health check endpoint:
GET /health- Returns application status
# Start all services (database, pgAdmin, and application)
docker-compose up -d
# Stop all services
docker-compose down
# View logs
docker-compose logs -f# Start only database and pgAdmin
docker-compose up -d db pgadmin# Run tests (when implemented)
pytest
# Run tests with coverage
pytest --cov=appMain dependencies include:
- fastapi: Web framework
- uvicorn: ASGI server
- sqlalchemy: ORM
- alembic: Database migrations
- pydantic: Data validation
- python-jose: JWT handling
- passlib: Password hashing
- asyncpg: PostgreSQL driver
See requirements.txt for complete list.
- Use environment variables for all configuration
- Enable HTTPS in production
- Use a production ASGI server like Gunicorn with Uvicorn workers
- Set up proper logging and monitoring
- Use a reverse proxy like Nginx
- Implement rate limiting
- Set up database connection pooling
gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter any issues or have questions, please:
- Check the existing issues in the repository
- Create a new issue with detailed description
- Include error logs and steps to reproduce
See CHANGELOG.md for a detailed history of changes.