tenants2fast-fastapi
🏢 Multi-tenancy management for FastAPI — tenant isolation, JWT-aware middleware, and permission-gated endpoints, all wired up in minutes.
Part of the *2fast-fastapi ecosystem: oauth2fast-fastapi → permissions2fast-fastapi → tenants2fast-fastapi.
📖 Conventions reference: this package follows the 2fast-handbook for ecosystem conventions (structure, versioning, README, commits, release).
Features
- 🔐 JWT-aware
TenantMiddleware— extracts user from Bearer token and sets tenant context automatically on every request - 🏗️ Isolated tenant databases — each tenant gets its own PostgreSQL database, created and initialized at runtime
- 🗂️
TenantandTenantUserSQLModel models — ready-to-use ORM models with audit timestamps - ⚡ Redis caching — tenant data and user permissions are cached via
permissions2fast-fastapi - 🔒
require_permissiondependency — guard any route with a single line using the RBAC system frompermissions2fast-fastapi
Installation
pip install tenants2fast-fastapi
Or with uv:
uv add tenants2fast-fastapi
Quick Start
from fastapi import Depends, FastAPI
from tenant2fast_fastapi import (
TenantMiddleware,
get_current_tenant,
get_current_user,
require_permission,
)
app = FastAPI()
# 1. Register the middleware
app.add_middleware(TenantMiddleware)
# 2. Use dependencies in your endpoints
@app.get("/me/tenant")
async def my_tenant(tenant=Depends(get_current_tenant)):
return {"name": tenant.name, "slug": tenant.slug}
@app.get("/reports", dependencies=[Depends(require_permission("/reports", "GET"))])
async def reports(user=Depends(get_current_user)):
return {"user": user.email}
See examples/basic_usage.py for a more complete example.
Configuration
All settings use the TENANT_ prefix and can be provided via environment variables or a .env file.
| Variable | Default | Description |
|---|---|---|
TENANT_DB_PREFIX |
tenant_ |
Prefix for per-tenant database names |
TENANT_SUPERUSER_DB__HOSTNAME |
localhost |
PG host for superuser operations |
TENANT_SUPERUSER_DB__PORT |
5432 |
PG port |
TENANT_SUPERUSER_DB__USERNAME |
postgres |
PG superuser username |
TENANT_SUPERUSER_DB__PASSWORD |
postgres |
PG superuser password |
TENANT_SUPERUSER_DB__NAME |
postgres |
Default DB for superuser connection |
TENANT_MAX_TENANT_CONNECTIONS |
5 |
Connection pool size per tenant |
In addition, all variables required by oauth2fast-fastapi (JWT, DB connections, mail) and permissions2fast-fastapi (Redis) must be set — see their respective READMEs.
Public API
from tenant2fast_fastapi import (
Tenant, # SQLModel ORM model (table: tenants)
TenantUser, # Many-to-many User ↔ Tenant (table: tenant_users)
TenantMiddleware, # Starlette BaseHTTPMiddleware
get_current_tenant, # FastAPI dependency → Tenant
get_current_user, # FastAPI dependency → User (from oauth2fast-fastapi)
require_permission, # Dependency factory → checks RBAC + cache
create_tenant_database, # async — creates a PG database for a tenant
get_tenant_engine, # returns (cached) AsyncEngine for a tenant DB
initialize_tenant_schema, # async — runs SQLModel.metadata.create_all on tenant DB
)
Development
# Clone and install in editable mode with dev + test dependencies
git clone https://github.com/AngelDanielSanchezCastillo/tenants2fast-fastapi
cd tenants2fast-fastapi
uv sync --group dev --group test
# Copy .env and adjust to your local setup
cp .env .env.local # or just edit .env directly
# Run tests (requires PostgreSQL + Redis)
uv run pytest tests/ -v
# Build distribution
uv build
Related Packages
📋 Naming Conventions
This package follows consistent naming conventions for models and database tables:
Model Classes (Python)
- Singular PascalCase
- Examples:
User,Role,Permission,Category,Route
Database Tables
- Plural snake_case
- Examples:
users,roles,permissions,categories,routes
Many-to-Many Join Tables
- Plural snake_case on both table names
- Alphabetical order of the two table names
- Examples:
role_users(r < u),permission_roles(p < r),permission_routes(p < r)
Tenant-Local vs Auth DB Models
- Auth DB:
Tenant(table:tenants),TenantUser(table:tenant_users) - maps users ↔ tenants - Tenant DB:
User,Role,Permission,Category,Route- local tenant entities
Generic Categories
- Use
Categoryfor generic categorization (notPermissionCategory) - Can be reused across different entity types
License
Metadata
Release files for tenants2fast-fastapi 0.7.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tenants2fast_fastapi-0.7.2.tar.gz | 57.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tenants2fast_fastapi-0.7.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 113.0 kB
Release files / tenants2fast_fastapi-0.7.2.tar.gz
| Download URL | tenants2fast_fastapi-0.7.2.tar.gz |
|---|---|
| Size | 57.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f10f0d7573c13a4e10b34a5099d3da9a2a28c181d7aac7da7d5d90b77004e000
|
|
BLAKE2b-256 checksum How to use checksums |
fdb65001cf9368be48218b763151d31d1e058006007f5ab7814cd2b05dec611a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Release files / tenants2fast_fastapi-0.7.2-py3-none-any.whl
| Download URL | tenants2fast_fastapi-0.7.2-py3-none-any.whl |
|---|---|
| Size | 55.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d2fdffb00d02695cbe12d65b6dfde8c5c952bcc52eed061f209a047c56740b03
|
|
BLAKE2b-256 checksum How to use checksums |
6aa10d75971ae377f2b926f47f6baa0bb730519d2e5a7b8a190bb4ee3e61a966
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|