Skip to main content

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

  1. TenantMiddleware extracts tenant_id from the request (e.g., from JWT via auth middleware)
  2. TenantContext stores it in a contextvar (async-safe)
  3. SQLAlchemy event listener injects SET LOCAL app.current_tenant on each transaction
  4. 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

Requirements

  • Python 3.11+
  • PostgreSQL 14+ (RLS support)

License

MIT

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)

Source distribution for ulfblk-multitenant 0.1.0
File Size Uploaded
ulfblk_multitenant-0.1.0.tar.gz 4.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ulfblk-multitenant 0.1.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page