---
title: Multi-Tenancy
description: How Dispatch scopes jobs and workflows to app and organization contexts.
---

Multi-tenancy support is built into Dispatch via the `scope` package and the `ScopeAppID` / `ScopeOrgID` fields on every entity. It integrates naturally with the Forge framework but degrades gracefully in standalone mode.

## Scope fields on entities

Every major entity carries scope fields:

| Entity | Fields |
|--------|--------|
| `job.Job` | `ScopeAppID`, `ScopeOrgID` |
| `workflow.Run` | `ScopeAppID`, `ScopeOrgID` |
| `cron.Entry` | `ScopeAppID`, `ScopeOrgID` |
| `dlq.Entry` | `ScopeAppID`, `ScopeOrgID` |

These fields are populated automatically from the context at enqueue time via `scope.Capture(ctx)`.

## The scope middleware

Add `middleware.Scope()` to the engine's middleware chain. It reads scope fields from the enqueued `Job` and injects them back into the handler's `context.Context`:

```go
eng := engine.Build(d,
    engine.WithMiddleware(middleware.Scope()),
)
```

Inside a job handler, retrieve the scope:

```go
import "github.com/xraph/dispatch/scope"

func(ctx context.Context, input MyInput) error {
    appID, orgID := scope.Capture(ctx)
    // use appID / orgID to scope database queries
    return nil
}
```

## The scope package

In standalone mode, `scope.Capture` returns empty strings (no-op):

```go
import "github.com/xraph/dispatch/scope"

appID, orgID := scope.Capture(ctx)        // "" in standalone mode
ctx = scope.Restore(ctx, appID, orgID)    // inject into context
```

When running inside the Forge framework, the scope package reads app and organization IDs from the Forge context automatically.

## Per-queue tenant routing

Combine scope with per-queue configuration to isolate tenant traffic:

```go
eng := engine.Build(d,
    engine.WithQueueConfig(
        queue.Config{Name: "tenant-acme",  MaxConcurrency: 5},
        queue.Config{Name: "tenant-beta",  MaxConcurrency: 2},
    ),
)

// Enqueue to a tenant-specific queue:
engine.EnqueueOnQueue(ctx, eng, SendEmail, input, "tenant-acme")
```
