A production-ready FastAPI server template, emphasizing performance and type safety. It includes a configurable set of features and options, allowing customization to retain or exclude components.
Built with FastAPI, Pydantic, Ruff, and MyPy.
Report Bug
·
Request Feature
- ⚡ Async and type safety by default
- 🛠️ CI/CD and tooling setup
- 🚀 High performance libraries integrated (orjson, uvloop, pydantic2)
- 📝 Loguru + picologging for simplified and performant logging
- 🐳 Dockerized and includes AWS deployment flow
- 🗃️ Several database implementations with sample ORM models (MySQL, Postgres, Timescale) & migrations
- 🔐 Optional JWT authentication and authorization
- 🌐 AWS Lambda functions support
- 🧩 Modularized features
- 📊 Prometheus metrics
- 📜 Makefile commands
- 🗺️ Route profiling
- Requirements
- Installation
- Environment Specific Configuration
- Upgrading Dependencies
- Databases
- JWT Auth
- Project Structure
- Makefile Commands
- Contributing
-
Fork this repo (How to create a private fork)
-
Install UV Package Manager: Follow the installation instructions at https://github.com/astral-sh/uv
-
Set up the virtual environment and install dependencies:
uv venv # On macOS and Linux source .venv/bin/activate # On Windows .venv\Scripts\activate # Install main dependencies uv pip install -r requirements.txt # Install development dependencies (optional) uv pip install -r dev-requirements.txt
-
Install Docker
-
Start your Docker services:
docker compose up
-
Clone
.env.example
to.env
and update the values:# macOS and Linux cp .env.example .env # Windows (PowerShell) Copy-Item .env.example .env
You can use this command to generate secret keys:
# macOS and Linux openssl rand -hex 128 # Windows (PowerShell) $bytes = New-Object byte[] 128; (New-Object Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes); [System.BitConverter]::ToString($bytes) -Replace '-'
-
Run the server:
uvicorn main:server --reload
Note: If you need to update dependencies, you can modify the requirements.txt
or dev-requirements.txt
files directly and then run uv pip install -r requirements.txt
or uv pip install -r dev-requirements.txt
respectively.
This project uses environment-specific configuration files and symbolic links to manage different environments such as development, production, and staging. Follow the steps below for your operating system to set up the desired environment.
# macOS, linux
ln -s <TARGET>.env .env
# example: ln -s prod.env .env
# windows
mklink .env <TARGET>.env
# example: mklink .env prod.env
To access the database shell, run this command
python -i shell.py
The shell.py
script will be loaded including the database session and models.
To do a database migration, follow the steps below.
-
Update
database/models.py
with the changes you want -
Run this command to generate the migration file in
migrations/versions
alembic revision --autogenerate -m "Describe your migration"
-
Check the newly generated migration file and verify that it generated correctly.
-
Run this command to apply the migration
alembic upgrade head
⛔️ Autogenerated migrations cannot detect these changes:
- Changes of table name
- Changes of column name
- Anonymously named constraints
- Special SQLAlchemy types such as Enum when generated on a backend which doesn’t support ENUM directly
These changes will need to be migrated manually by creating an empty migration file and then writing the code to create the changes.
# Manual creation of empty migration file
alembic revision -m "Describe your migration"
Run this command to revert every migration back to the beginning.
alembic downgrade base
In this FastAPI template, JSON Web Tokens (JWT) can be optionally utilized for authentication. This documentation section elucidates the JWT implementation and related functionalities.
The JWT implementation can be found in the module: app/auth/jwt.py. The primary functions include:
- Creating access and refresh JWT tokens.
- Verifying and decoding a given JWT token.
- Handling JWT-based authentication for FastAPI routes.
If a user associated with a JWT token is not found in the database, a new user will be created. This is managed by the get_or_create_user function. When a token is decoded and the corresponding user ID (sub field in the token) is not found, the system will attempt to create a new user with that ID.
A nonce is an arbitrary number that can be used just once. It's an optional field in the JWT token to ensure additional security. If a nonce is used:
- It is stored in Redis for the duration of the refresh token's validity.
- It must match between access and refresh tokens to ensure their pairing.
- Its presence in Redis is verified before the token is considered valid.
Enabling nonce usage provides an additional layer of security against token reuse, but requires Redis to function.
The JWT token payload structure is defined in `app/types/jwt.py`` under the JWTPayload class. If you wish to add more fields to the JWT token payload:
-
Update the TokenData and JWTPayload class in `app/types/jwt.py`` by adding the desired fields.
class JWTPayload(BaseModel): # ... existing fields ... new_field: Type class TokenData(BaseModel): # ... existing fields ... new_field: Type
TokenData is separated from JWTPayload to make it clear what is automatically filled in and what is manually added. Both classes must be updated to include the new fields.
-
Wherever the token is created, update the payload to include the new fields.
from app.auth.jwt import create_jwt from app.types.jwt import TokenData payload = TokenData( sub='user_id_1', field1='value1', # ... all fields ... ) access_token, refresh_token = create_jwt(payload)
Remember, the JWT token has a size limit. The more data you include, the bigger your token becomes, so ensure that you only include essential data in the token payload.
📄 main.py - Server entry point
📁 .github/ - Github specific files
📁 app/ - Application code
├── 📁 api - API endpoints and middleware
├── 📁 auth - Authentication / authorization
├── 📁 cache - Redis code and caching functions
├── 📁 core - Core configuration
├── 📁 db - Database connections
├── 📁 discord - Discord library for auth (optional)
├── 📁 lmbd - Holds AWS lambda functions
├── 📁 migrations - Database migrations
├── 📁 models - Database ORM models
├── 📁 types - Type definitions
└── 📁 util - Helper functions
Make files are used to run common commands. You can find the list of commands in the Makefile
file.
To use these commands, first copy make-env-example.sh
to make-env.sh
and update the values.
# macOS
cp make-env-example.sh make-env.sh
# windows (powershell)
copy make-env-example.sh make-env.sh
Remember to make the file executable
chmod +x make-env.sh
Then you can run the commands like this
./make-env.sh <command>
Try it with the help command, which will list all the available commands.
./make-env.sh help
- Fork the Repository: Start by forking the repository to your own GitHub account.
- Clone the Forked Repository: Clone the fork to your local machine.
- Create a New Branch: Always create a new branch for your changes.
- Make Your Changes: Implement your changes.
- Run Tests: Make sure to test your changes locally.
- Submit a Pull Request: Commit and push your changes, then create a pull request against the main branch.