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.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tenants2fast_fastapi-0.8.0.tar.gz | 75.2 kB | Without provenance | Details for tenants2fast_fastapi-0.8.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tenants2fast_fastapi-0.8.0-py3-none-any.whl | Python 3 | none | any | Details for tenants2fast_fastapi-0.8.0-py3-none-any.whl |
Total release size: 142.7 kB
Release files / tenants2fast_fastapi-0.8.0.tar.gz
| Download URL | tenants2fast_fastapi-0.8.0.tar.gz |
|---|---|
| Size | 75.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d7764706786392c1f5299153e5c78e612c1e51d6cb39222a28a129b2b3b32094
|
|
BLAKE2b-256 checksum How to use checksums |
e4785dd262e9404f081a24c3b0a01bb45b650788aa28f02ac39713b8bfd80d77
|
| 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.8.0-py3-none-any.whl
| Download URL | tenants2fast_fastapi-0.8.0-py3-none-any.whl |
|---|---|
| Size | 67.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be925cb114a877e892c9519bb15e0658e02e7bd3aa2ef736286da2e83535f54b
|
|
BLAKE2b-256 checksum How to use checksums |
3f6e3e8463afc9b36a18f97ce37186b0ae271c78a3588b4196d50588773dae89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.9
|
Security for tenants2fast-fastapi 0.8.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.