Skip to content

fastapi-tenancy

Production-ready multi-tenancy for FastAPI.
Four isolation strategies. Five resolution strategies. Full async support. 95%+ test coverage.


At a glance

Python
from contextlib import asynccontextmanager
from typing import Annotated

from fastapi import Depends, FastAPI
from sqlalchemy.ext.asyncio import AsyncSession

from fastapi_tenancy import TenancyConfig, TenancyManager, TenancyMiddleware
from fastapi_tenancy.dependencies import get_current_tenant, make_tenant_db_dependency
from fastapi_tenancy.storage.database import SQLAlchemyTenantStore

# 1. Configure
config = TenancyConfig(
    database_url="postgresql+asyncpg://user:pass@localhost/myapp",
    resolution_strategy="header",   # read X-Tenant-ID header
    isolation_strategy="schema",    # schema-per-tenant
)

# 2. Wire
store   = SQLAlchemyTenantStore(config.database_url)
manager = TenancyManager(config, store)

# 3. App
@asynccontextmanager
async def lifespan(app: FastAPI):
    await manager.initialize()
    yield
    await manager.close()

app = FastAPI(lifespan=lifespan)
app.add_middleware(TenancyMiddleware, manager=manager, excluded_paths=["/health"])

# 4. Tenant-scoped session per request
get_db = make_tenant_db_dependency(manager)

@app.get("/orders")
async def list_orders(session: Annotated[AsyncSession, Depends(get_db)]):
    # session is already pointing at the current tenant's schema
    result = await session.execute(select(Order))
    return result.scalars().all()

Isolation strategies

Strategy Mechanism Databases Best for
schema Dedicated schema per tenant, search_path set per-connection PostgreSQL, MSSQL, SQLite* Most SaaS apps
database Separate database per tenant, LRU engine cache PostgreSQL, MySQL Strict regulatory isolation
rls Shared tables, PostgreSQL RLS policies, SET LOCAL GUC PostgreSQL only Large tenant counts
hybrid Route by tenant tier โ€” premium โ†’ schema, standard โ†’ rls PostgreSQL Tiered SaaS products

*SQLite falls back to table-name prefixing.


Installation

Bash
pip install fastapi-tenancy
Bash
pip install "fastapi-tenancy[postgres]"
Bash
pip install "fastapi-tenancy[mysql]"
Bash
pip install "fastapi-tenancy[full]"

Installs: asyncpg ยท redis[hiredis] ยท PyJWT ยท alembic