ulfblk-multitenant
PostgreSQL Row-Level Security (RLS) transparent multitenancy for FastAPI + SQLAlchemy. The developer never writes tenant filtering code manually.
Part of Bloques Reciclables - an open source ecosystem of reusable code blocks.
Installation
uv add ulfblk-multitenant
# or
pip install ulfblk-multitenant
How It Works
- TenantMiddleware extracts
tenant_idfrom the request (e.g., from JWT via auth middleware) - TenantContext stores it in a
contextvar(async-safe) - SQLAlchemy event listener injects
SET LOCAL app.current_tenanton each transaction - PostgreSQL RLS policies filter rows automatically
The developer writes normal queries - RLS handles isolation transparently.
Quick Start
1. Generate RLS SQL
from ulfblk_multitenant.rls import generate_rls_sql
# Generate and execute in your migration
sql = generate_rls_sql("orders", tenant_column="tenant_id")
# Enables RLS, creates tenant_isolation policy
2. Configure SQLAlchemy
from sqlalchemy.ext.asyncio import create_async_engine
from ulfblk_multitenant.rls import apply_rls
engine = create_async_engine("postgresql+asyncpg://...")
apply_rls(engine) # registers the event listener
3. Add Middleware
from fastapi import FastAPI
from ulfblk_multitenant.rls import TenantMiddleware
app = FastAPI()
# Default: reads tenant_id from request.state.tenant_id
app.add_middleware(TenantMiddleware)
# Or custom extractor:
app.add_middleware(
TenantMiddleware,
tenant_extractor=lambda req: req.headers.get("X-Tenant-ID"),
)
4. Use TenantContext Directly
from ulfblk_multitenant.context import get_current_tenant, set_current_tenant, clear_current_tenant
# Set manually (useful in background tasks, scripts)
ctx = set_current_tenant(
tenant_id="acme-123",
tenant_slug="acme",
tenant_name="ACME Corp",
)
# Read current tenant
tenant = get_current_tenant()
if tenant:
print(f"Current tenant: {tenant.tenant_id}")
# Clear
clear_current_tenant()
With ulfblk-auth
The typical setup combines ulfblk-auth JWT middleware with ulfblk-multitenant:
from fastapi import FastAPI
from ulfblk_core.middleware import RequestIDMiddleware
from ulfblk_multitenant.rls import TenantMiddleware, apply_rls
app = FastAPI()
# Middleware stack (order matters - last added runs first)
app.add_middleware(TenantMiddleware) # 3. Set tenant context from JWT
# ... auth middleware sets request.state.tenant_id ...
app.add_middleware(RequestIDMiddleware) # 1. Set request ID
# SQLAlchemy RLS
apply_rls(engine)
# Now all queries are automatically filtered by tenant
@app.get("/orders")
async def list_orders(session: AsyncSession = Depends(get_session)):
result = await session.execute(select(Order))
return result.scalars().all() # only current tenant's orders
Dependencies
- ulfblk-core
- SQLAlchemy 2.0+ (async)
- asyncpg
Requirements
- Python 3.11+
- PostgreSQL 14+ (RLS support)
License
Metadata
Release files for ulfblk-multitenant 0.1.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 | |
|---|---|---|---|
| ulfblk_multitenant-0.1.0.tar.gz | 4.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ulfblk_multitenant-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 10.8 kB
Release files / ulfblk_multitenant-0.1.0.tar.gz
| Download URL | ulfblk_multitenant-0.1.0.tar.gz |
|---|---|
| Size | 4.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d97da7cd4f2048386cb0bc22c44fd28339d37701d4d56cc8b4775792b56536e
|
|
BLAKE2b-256 checksum How to use checksums |
a350259408d58122b68921ac57970200e6558814ceec71fd1dd4ab4e35478bfb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / ulfblk_multitenant-0.1.0-py3-none-any.whl
| Download URL | ulfblk_multitenant-0.1.0-py3-none-any.whl |
|---|---|
| Size | 6.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be832c020d3dd984732c9454bbe0cfcb6c4647bd0463f4149ff57719ef0588e5
|
|
BLAKE2b-256 checksum How to use checksums |
338649e57ceeb65b3a7201f1da3d8a4e441bca9c7d0339ff4a66d0a32b1f63a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|