Appearance
Tenancy & Request Context
LOOT provides user-level tenancy by default. Each unique combination of account, database name, and tenant gets its own isolated database instance. Your account identifier is simply the JWK thumbprint of your public key—no registration required.
How Tenancy Works
Every database is isolated by three identifiers from your JWT:
- Account: The JWK thumbprint of your signing key (
subclaim) - Database name: The logical name of your application (
db.name) - Tenant: A sub-identifier within your database (
db.tenant)
This means alice/chat-app/room-1 and alice/chat-app/room-2 are completely separate databases, as are alice/chat-app/room-1 and bob/chat-app/room-1. Each gets its own schema, data, and access control rules.
Request Context
You can create custom tables and use the before and after JWT claims to inject per-request context data. This is essential for implementing user-scoped filters and rules.
Schema
Before SQL
After SQL
Instead SQL
SQL Query
Results
The before claim runs privileged SQL before your main query, allowing you to set up context tables with user IDs, permissions, or other session data. The after claim cleans up this context after execution.
Multi-Tenant Patterns
Per-User Databases
Set db.tenant to the user ID for complete user isolation:
javascript
{
"db": {
"name": "my-app",
"tenant": "user-alice"
}
}Per-Room/Document Databases
Set db.tenant to the room or document ID for shared spaces:
javascript
{
"db": {
"name": "chat-app",
"tenant": "room-general"
}
}Shared Database with Row-Level Security
Use a single tenant with request context for fine-grained access control:
javascript
{
"db": {
"name": "my-app",
"tenant": "shared"
},
"before": "INSERT INTO _context (user_id) VALUES ('alice')"
}Each pattern has different trade-offs for isolation, performance, and complexity. LOOT's flexibility lets you choose the right approach for your use case.