Skip to content

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 (sub claim)
  • 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
Initializing...

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.