SQLModel for FastAPI
Comprehensive skill for building database-driven FastAPI applications with SQLModel, PostgreSQL, and SQLAlchemy.
Quick Start
Basic Setup
# Install dependencies
pip install sqlmodel psycopg2-binary alembic pytest
# Create database models
from sqlmodel import SQLModel, Field, create_engine
from typing import Optional
class User(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
username: str = Field(unique=True, index=True)
email: str = Field(unique=True, index=True)
# Create engine and tables
engine = create_engine("postgresql://user:pass@localhost/db")
SQLModel.metadata.create_all(engine)
# Use in FastAPI
from fastapi import FastAPI, Depends
from sqlmodel import Session
app = FastAPI()
def get_session():
with Session(engine) as session:
yield session
@app.post("/users")
def create_user(user: User, session: Session = Depends(get_session)):
session.add(user)
session.commit()
session.refresh(user)
return user
Reference Documentation
This skill includes comprehensive reference files organized by topic. Read the relevant file based on your needs:
Core Topics
- •
models.md - SQLModel basics, field types, constraints, table configuration, request/response models, computed fields, JSON fields, UUID keys, composite primary keys
- •
relationships.md - One-to-many, one-to-one, many-to-many relationships, cascade deletes, self-referential relationships, lazy vs eager loading, association object pattern
- •
sessions.md - Database engine setup, session management, FastAPI dependency injection, connection pooling, async sessions, multiple databases, transaction control
- •
crud.md - Create, read, update, delete operations, bulk operations, upsert patterns, soft deletes, transaction patterns, FastAPI endpoint integration
- •
queries.md - Where clauses, ordering, pagination, aggregations, joins, subqueries, dynamic filtering, full-text search, JSON queries, window functions, exists queries
Advanced Topics
- •
migrations.md - Alembic setup and configuration, creating and applying migrations, migration operations, data migrations, branching and merging, production workflow, FastAPI integration
- •
testing.md - Test database setup, FastAPI TestClient integration, testing CRUD operations, testing relationships, fixtures, parametrized tests, database isolation, coverage
- •
performance.md - Connection pooling optimization, query optimization, N+1 problem solutions, indexing strategies, bulk operations, pagination best practices, caching, read replicas, batch processing
- •
integration.md - FastAPI project structure, application lifespan, router implementation, custom dependencies, response models with relationships, error handling, middleware, background tasks, WebSocket integration
- •
advanced.md - Transaction management, nested transactions, cascading deletes, soft deletes, event listeners, optimistic locking, database constraints, custom field types, security best practices, monitoring and logging
Common Workflows
Creating a New Model
- •Define the model in your models file
- •Add relationships if needed
- •Create request/response schemas
- •Generate migration:
alembic revision --autogenerate -m "Add model" - •Review and apply migration:
alembic upgrade head - •Implement CRUD functions
- •Create API endpoints
- •Write tests
Setting Up Database
- •Install dependencies:
pip install sqlmodel psycopg2-binary alembic - •Create database configuration in
database.py - •Define models in
models.py - •Initialize Alembic:
alembic init alembic - •Configure Alembic for SQLModel (see migrations.md)
- •Create initial migration
- •Set up dependency injection for sessions
Optimizing Performance
- •Add indexes on frequently queried columns (see models.md)
- •Use eager loading for relationships (see relationships.md)
- •Configure connection pooling (see sessions.md)
- •Implement pagination (see queries.md)
- •Use bulk operations for multiple inserts/updates (see crud.md)
- •Add query caching if needed (see performance.md)
Adding Relationships
- •Define foreign key in child model
- •Add
Relationshipfield in both models - •Use
back_populatesto link them - •For many-to-many, create link table
- •Configure cascade behavior if needed (see relationships.md)
- •Update migrations
- •Test relationship loading
When to Use Each Reference
- •Starting a new project? Read: sessions.md → models.md → integration.md
- •Need relationships? Read: relationships.md
- •Writing queries? Read: queries.md
- •Performance issues? Read: performance.md → queries.md
- •Setting up testing? Read: testing.md
- •Database migrations? Read: migrations.md
- •Building CRUD endpoints? Read: crud.md → integration.md
- •Advanced features? Read: advanced.md
Best Practices Summary
Model Design
- •Use
Optional[int]withdefault=Nonefor auto-increment primary keys - •Add indexes to foreign keys and frequently queried fields
- •Use enums for status/category fields
- •Separate table models from request/response models
- •Use mixins for common fields (created_at, updated_at)
Session Management
- •Always use dependency injection in FastAPI endpoints
- •Use context managers (
with Session()) for manual sessions - •Configure connection pooling for production
- •Set
pool_pre_ping=Trueto handle stale connections
Queries
- •Use eager loading to avoid N+1 queries
- •Add appropriate indexes before querying large datasets
- •Use cursor-based pagination for large result sets
- •Use
select()for all queries instead of legacy query API
Migrations
- •Always review auto-generated migrations before applying
- •Test migrations locally before production
- •Make migrations reversible (implement both upgrade and downgrade)
- •Use separate migrations for schema and data changes
Testing
- •Use SQLite in-memory database for tests
- •Use fixtures for test data
- •Override FastAPI dependencies in tests
- •Test both success and failure cases
Performance
- •Index foreign keys and frequently queried columns
- •Use bulk operations for multiple inserts/updates
- •Configure appropriate pool sizes based on load
- •Monitor slow queries and optimize them
Security
- •Never use string formatting for queries (use parameterized queries)
- •Hash passwords with bcrypt or similar
- •Validate all user input with Pydantic
- •Use environment variables for database credentials
- •Handle database errors gracefully without exposing internals
Example Project Structure
app/
├── __init__.py
├── main.py # FastAPI app with lifespan
├── database.py # Engine and session setup
├── models.py # SQLModel definitions
├── crud.py # CRUD operations
├── dependencies.py # FastAPI dependencies
├── config.py # Settings with pydantic-settings
├── routers/
│ ├── __init__.py
│ ├── users.py
│ └── posts.py
└── tests/
├── __init__.py
├── conftest.py # Test fixtures
├── test_users.py
└── test_posts.py
alembic/
├── versions/
│ └── *.py # Migration files
├── env.py # Alembic configuration
└── script.py.mako
.env # Environment variables
alembic.ini # Alembic config
pyproject.toml # Dependencies
Troubleshooting
Common Issues
Import errors with SQLModel models:
- •Ensure all models are imported in
alembic/env.py - •Import models before calling
SQLModel.metadata.create_all()
N+1 query problems:
- •Use
selectinload()orjoinedload()for relationships - •Check query logs with
echo=Trueon engine
Connection pool exhausted:
- •Increase
pool_sizeandmax_overflow - •Ensure sessions are properly closed (use context managers)
- •Check for long-running transactions
Migration conflicts:
- •Use
alembic headsto check for multiple heads - •Merge branches with
alembic merge - •Resolve conflicts manually in migration files
Slow queries:
- •Add indexes on queried columns
- •Use
EXPLAIN ANALYZEto check query plan - •Consider using read replicas for read-heavy workloads
Additional Resources
For detailed information on specific topics, refer to the reference files in the references/ directory. Each file contains comprehensive examples and patterns for that specific area.