A comprehensive FastAPI boilerplate with SQLAlchemy, PostgreSQL, Redis caching, rate limiting, and RBAC.
- FastAPI - High-performance web framework
- SQLAlchemy - Async ORM with PostgreSQL support
- Alembic - Database migrations
- Redis - Caching and rate limiting
- RBAC - Role-based access control
- Docker - Containerization
- Environment Management - Separate development and production environments
- UV - Fast Python package installer
- Python 3.13+
- UV (Python package installer and resolver)
- Docker and Docker Compose (for containerized deployment)
- PostgreSQL (for local development)
- Redis (for local development)
- Note for Windows users: Redis doesn't officially support Windows. Use WSL (Windows Subsystem for Linux) or Docker. See Running Redis on Windows Using WSL section below.
fastapi-boilerplate/
├── src/
│ ├── app/
│ │ ├── api/ # API routes
│ │ │ ├── v1/ # API version 1
│ │ │ │ ├── endpoints/ # API endpoints
│ │ │ │ └── router.py # API router
│ │ │ ├── deps.py # API dependencies
│ │ │ └── router.py # Main API router
│ │ ├── models/ # SQLAlchemy models
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # Business logic
│ │ └── main.py # FastAPI application
│ ├── core/
│ │ ├── cache/ # Redis cache
│ │ ├── db/ # Database
│ │ ├── utils/ # Utilities
│ │ ├── config.py # Configuration
│ │ ├── exceptions.py # Exception handlers
│ │ ├── logging.py # Logging configuration
│ │ ├── middleware.py # Middleware
│ │ └── security.py # Security utilities
│ └── settings/
│ └── run.py # Run script
├── envs/ # Environment variables
├── migrations/ # Alembic migrations
├── tests/ # Tests
├── .env # Environment variables (copied from envs)
├── .gitignore # Git ignore file
├── alembic.ini # Alembic configuration
├── docker-compose.yml # Docker Compose configuration
├── Dockerfile # Docker configuration
├── pyproject.toml # Project configuration
└── README.md # Project documentation
- Clone the repository:
git clone <your-repository-url>
cd fastapi-boilerplate
- Install dependencies using UV (this will install the latest versions of all packages):
# On Windows
install_latest.bat
# On Unix/Linux/Mac
python -m venv .venv
source .venv/bin/activate
uv pip install -e .
- Set up PostgreSQL and Redis locally or using Docker:
docker-compose up -d postgres redis
- Initialize the database:
uv run init-db
- Run the development server:
uv run dev
- Build and run the Docker containers:
docker-compose up -d
- Run the development server:
uv run dev
- Run the production server:
uv run prod
- Format code using Ruff:
uv run format
- Lint code using Ruff:
uv run lint
- Initialize the database:
uv run init-db
This project uses UV along with Poetry for package management. UV is a fast Python package installer and resolver.
- Install all packages defined in pyproject.toml:
uv pip install -e .
- Add a new package:
uv pip install package_name
Then add it to the dependencies list in pyproject.toml.
Redis doesn't officially support Windows. The recommended approach is to use Windows Subsystem for Linux (WSL).
- Open PowerShell as Administrator and run:
wsl --install
-
Restart your computer when prompted.
-
After restart, a Ubuntu terminal will open. Set up your Linux username and password.
- Open your WSL terminal (Ubuntu) and update the package lists:
sudo apt update
- Install Redis:
sudo apt install redis-server
- Start the Redis service:
sudo service redis-server start
- Verify Redis is running:
redis-cli ping
If Redis is running correctly, it should respond with "PONG".
- Edit the Redis configuration file:
sudo nano /etc/redis/redis.conf
-
Find the line with
bind 127.0.0.1 ::1
and change it tobind 0.0.0.0
to allow connections from Windows. -
Find the line that contains
supervised no
and change it tosupervised systemd
. -
Save and exit (Ctrl+O, Enter, Ctrl+X).
-
Restart Redis:
sudo systemctl restart redis-server
Update your .env.development
file to point to the WSL Redis instance:
REDIS_URL=redis://localhost:6379/0
Start Redis:
sudo service redis-server start
Stop Redis:
sudo service redis-server stop
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
The application uses environment variables for configuration. These are stored in the envs/
directory and copied to .env
when running the application.
# Application settings
APP_ENV=development
DEBUG=true
HOST=127.0.0.1
PORT=8000
RELOAD=true
LOG_LEVEL=DEBUG
SECRET_KEY=dev_secret_key_change_in_production
# Database settings
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/fastapi_dev
# Redis settings
REDIS_URL=redis://localhost:6379/0
# Rate limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_DEFAULT=100/minute
# CORS settings
CORS_ORIGINS=http://localhost:3000,http://localhost:8000
# Application settings
APP_ENV=production
DEBUG=false
HOST=0.0.0.0
PORT=8000
RELOAD=false
LOG_LEVEL=INFO
SECRET_KEY=your_production_secret_key_here
# Database settings
DATABASE_URL=postgresql+asyncpg://postgres:postgres@postgres:5432/fastapi_prod
# Redis settings
REDIS_URL=redis://redis:6379/0
# Rate limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_DEFAULT=60/minute
# CORS settings
CORS_ORIGINS=https://yourdomain.com
The application uses JWT tokens for authentication. The following endpoints are available:
POST /api/v1/auth/login
- Login with username and passwordPOST /api/v1/auth/refresh
- Refresh access token
This project implements a comprehensive Role-Based Access Control (RBAC) system that provides flexible and granular access control.
-
Users
- Can have multiple roles
- Can be superusers (bypass all permission checks)
- Authenticated using JWT tokens
-
Roles
- Named collections of permissions (e.g., "admin", "editor", "viewer")
- Can have multiple permissions
- Users can have multiple roles
-
Permissions
- Defined by resource and action pairs (e.g., "posts:create", "users:read")
- Can be assigned to roles
- Superusers automatically have all permissions
Permissions follow the format: resource:action
Common actions include:
create
: Create new resourcesread
: View resourcesupdate
: Modify existing resourcesdelete
: Remove resources*
: All actions on a resource
Examples:
# Full access to posts
Permission(resource="posts", action="*")
# Read-only access to users
Permission(resource="users", action="read")
# Create and update products
Permission(resource="products", action="create")
Permission(resource="products", action="update")
- Protecting API Endpoints
from src.app.api.deps import has_permission
@router.post("/posts/")
async def create_post(
post: PostCreate,
current_user: User = Depends(has_permission("posts", "create"))
):
# Only users with 'posts:create' permission can access this endpoint
pass
@router.get("/users/")
async def list_users(
current_user: User = Depends(has_permission("users", "read"))
):
# Only users with 'users:read' permission can access this endpoint
pass
- Creating Roles and Permissions
# Create an editor role
editor_role = Role(
name="editor",
description="Can manage blog posts"
)
# Add permissions to the role
editor_permissions = [
Permission(resource="posts", action="create"),
Permission(resource="posts", action="update"),
Permission(resource="posts", action="read"),
]
editor_role.permissions.extend(editor_permissions)
- Assigning Roles to Users
# Assign editor role to user
user.roles.append(editor_role)
await db.commit()
- Superuser
- Has all permissions
- Created using
uv run createsuperuser
- Can manage other users and roles
- Creating a Superuser
# Using CLI
uv run createsuperuser
# Follow the prompts to enter email, username, and password
- API Endpoints for RBAC Management
POST /api/v1/roles/
- Create new roleGET /api/v1/roles/
- List all rolesPUT /api/v1/roles/{role_id}
- Update roleDELETE /api/v1/roles/{role_id}
- Delete rolePOST /api/v1/permissions/
- Create new permissionGET /api/v1/permissions/
- List all permissionsPUT /api/v1/permissions/{permission_id}
- Update permissionDELETE /api/v1/permissions/{permission_id}
- Delete permission
- Checking Permissions in Code
# Check if user has specific permission
for role in user.roles:
for permission in role.permissions:
if permission.resource == "posts" and permission.action == "create":
# User has permission to create posts
pass
# Using the dependency
from src.app.api.deps import has_permission
@router.post("/posts/")
async def create_post(
current_user: User = Depends(has_permission("posts", "create"))
):
# Only accessible to users with posts:create permission
pass
-
Permission Naming
- Use lowercase for resources and actions
- Use descriptive names (e.g., "user_profiles" instead of "profiles")
- Be consistent with action names (create, read, update, delete)
-
Role Design
- Follow the principle of least privilege
- Create roles based on job functions
- Avoid giving more permissions than necessary
- Document role purposes and permissions
-
Security Considerations
- Regularly audit role assignments
- Remove unused roles and permissions
- Keep superuser access limited
- Log permission checks and role changes
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Format your code (
uv run format
) - Lint your code (
uv run lint
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request