FolderStructure.dev

FastAPI with SQLModel Project Structure

SQLModel integration—one model for DB and API. Less boilerplate, same Pydantic validation.

#fastapi #python #api #sqlmodel #pydantic #sqlalchemy #orm
PNGPDF

Project Directory

myproject/
main.py
App factory, lifespan
app/
Application code
__init__.py
config.py
Pydantic settings
core/
__init__.py
database.py
Engine, session
models/
SQLModel models
__init__.py
user.py
User, UserCreate, UserRead
item.py
link_tables.py
Many-to-many
api/
__init__.py
deps.py
Session dependency
v1/
__init__.py
router.py
users.py
items.py
services/
__init__.py
user_service.py
item_service.py
tests/
__init__.py
conftest.py
Test DB fixtures
api/
__init__.py
test_users.py
test_items.py
requirements.txt
requirements-dev.txt
.env.example
.gitignore
pyproject.toml

Why This Structure?

SQLModel unifies Pydantic and SQLAlchemy—one class defines both your database table and API schema. No more duplicate model definitions. Created by the same author as FastAPI, it's designed to feel native.

Key Directories

  • app/models/-SQLModel classes—DB tables AND Pydantic schemas
  • app/models/user.py-User (table), UserCreate, UserRead (schemas)
  • app/api/deps.py-Session dependency for routes
  • app/services/-Business logic with typed models

Getting Started

  1. python -m venv venv && source venv/bin/activate
  2. pip install -r requirements.txt
  3. cp .env.example .env
  4. uvicorn main:app --reload
  5. Tables auto-created via SQLModel.metadata.create_all()

SQLModel Pattern

# app/models/user.py
from sqlmodel import SQLModel, Field

class UserBase(SQLModel):
    email: str
    name: str | None = None

class User(UserBase, table=True):
    id: int | None = Field(default=None, primary_key=True)

class UserCreate(UserBase):
    password: str

class UserRead(UserBase):
    id: int

Table vs Schema Models

Use table=True only on the main model that maps to a database table. Create/Read/Update variants inherit from a base class without table=True. This keeps your API schemas clean while reusing field definitions.

When To Use This

  • New FastAPI projects wanting minimal boilerplate
  • Teams tired of syncing Pydantic schemas with SQLAlchemy models
  • Projects with straightforward CRUD operations
  • When you want one source of truth for data shape
  • Prototypes that may grow into production apps

Trade-offs

  • Less mature-Smaller ecosystem than raw SQLAlchemy
  • Complex queries-May need to drop to SQLAlchemy for advanced cases
  • No Alembic integration-Migrations require manual setup

Testing Strategy

  • conftest.py-In-memory SQLite for fast tests
  • tests/api/-Test endpoints with test client
  • Model reuse-Same models in tests as production