> ## Documentation Index
> Fetch the complete documentation index at: https://docs.helix-db.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Tenancy

> For the complete documentation index optimized for AI agents, see [llms.txt](/llms.txt).

Multi-tenant architectures generally fall into one of three isolation levels.

## Isolation Levels

| Level                    | Description                                                                                                                 | Isolation                                                        | Resource efficiency                                                  |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
| **Infrastructure-level** | Separate database instance per tenant. Fully independent compute, storage, and networking.                                  | Strongest. No shared resources.                                  | Lowest. Each tenant pays the full cost of an idle cluster.           |
| **Namespace-level**      | Shared infrastructure, separate logical partitions (databases, schemas, or namespaces) per tenant.                          | Strong. Logical separation with shared compute.                  | Moderate. Shared compute, but metadata and indexes scale per tenant. |
| **Row-level**            | Shared infrastructure, shared data structures. Tenants distinguished by a property on every record, enforced at query time. | Application-enforced. Relies on consistent query-time filtering. | Highest. All tenants share indexes, caches, and storage.             |

## Row-Level Isolation in Helix Cloud

Helix Cloud focuses on row-level isolation, which lets you implement any tenancy model at the
application layer without structural constraints on the database. Adding a tenant is a write, not a
provisioning event.

Assign a tenant identifier as a property on every node and edge, index it with an equality index,
and filter every query on it so each request only sees its own tenant's data. This is the same
mechanism as any property-based filtering: secondary indexes make the lookup fast, and snapshot
isolation keeps concurrent tenants from interfering.

The model stays shared infrastructure throughout — one writer fleet, one reader fleet, shared caches
and secondary indexes. When search results also need isolating, vector and text search can use
[tenant-partitioned indexes](#tenant-partitioned-search-indexes).

### In Practice

The pattern is the same regardless of node label: declare an equality index on the tenant
property once, attach `tenant_id` to every node and edge that gets written, and filter every read
by `tenant_id`.

Declare the index once, as part of your schema setup write batch:

```rust theme={"languages":{"custom":["languages/helixql.json"]}}
g().create_index_if_not_exists(
    IndexSpec::node_equality("Doc", "tenant_id"),
)
```

Attach `tenant_id` to every node when it is written:

```rust theme={"languages":{"custom":["languages/helixql.json"]}}
g().add_n(
    "Doc",
    vec![
        ("tenant_id", PropertyInput::from("acme")),
        ("title", PropertyInput::from("Acme doc")),
    ],
)
```

Scope every read by the requesting tenant. Use the source-predicate form so the equality index
on `tenant_id` is hit directly:

```rust theme={"languages":{"custom":["languages/helixql.json"]}}
g().n_with_label_where(
    "Doc",
    SourcePredicate::eq("tenant_id", "acme"),
)
```

When the tenant predicate sits mid-traversal — for example after walking edges from a known
starting node — use `.where_(Predicate::eq("tenant_id", "acme"))`. The same scope rule applies
at every hop: edges that fan out across the graph remain tenant-scoped as long as every step
filters on the tenant property.

## What This Provides

* **Data isolation.** Queries scoped to a tenant ID never observe another tenant's data. Isolation
  is enforced by the query layer, not by network or infrastructure boundaries.
* **Shared infrastructure.** All tenants share the same writer, readers, caches, and object
  storage. No per-tenant provisioning, no per-tenant scaling configuration.
* **Uniform scaling.** Reader auto-scaling responds to aggregate query load across all tenants.
  A spike from one tenant benefits from the same scaling that serves all others.
* **Index efficiency.** Equality indexes on the tenant property resolve tenant-scoped queries
  without scanning unrelated data.
* **Full flexibility.** The application layer decides how tenancy is modeled, scoped, and
  enforced. Helix Cloud provides the primitives; the application owns the policy.

## Tenant-Partitioned Search Indexes

Tenant-partitioned search indexes are optional. They supplement row-level filtering with separate
physical search structures per tenant value.

### Vector Indexes

Vector indexes can optionally partition by a configured tenant property name. Helix reads that
property from each record and maintains a separate vector index for each distinct property value.
For example, if the tenant property name is `tenant_id`, records with different `tenant_id` values
land in different vector indexes. This keeps tenant-scoped search working sets smaller and allows
vector caches to warm, retain, and evict data at tenant granularity. Tenant-partitioned vector
indexes are the preferred way to isolate vector search results when that behavior is required.

The DSL surface for tenant-partitioned vector indexes:

```rust theme={"languages":{"custom":["languages/helixql.json"]}}
// Declare the index. The third argument is the property name Helix
// reads from each record to choose the tenant partition.
g().create_vector_index_nodes("Doc", "embedding", Some("tenant_id"))

// Insert a node with both the tenant property and the embedding.
g().add_n(
    "Doc",
    vec![
        ("tenant_id", PropertyInput::from("acme")),
        ("title", PropertyInput::from("Acme doc")),
        ("embedding", PropertyInput::from(vec![1.0f32, 0.0, 0.0])),
    ],
)

// kNN search scoped to a tenant. The tenant value selects the partition;
// no additional filtering is needed.
g().vector_search_nodes(
    "Doc",
    "embedding",
    vec![1.0f32, 0.0, 0.0],
    5,
    Some(PropertyValue::from("acme")),
)
```

### Text Indexes

Text indexes provide the same model for full-text search. The tenant property still means the
property name used to read the partition value from each record. Current text index validation
requires that property name to be `tenant_id`, so Helix maintains a separate text index for each
distinct `tenant_id` value. This keeps tenant-scoped full-text search working sets smaller and
allows local text-search caches to track active tenants more closely. Tenant-partitioned text
indexes are the preferred way to isolate full-text search results when that behavior is required.

The DSL surface for tenant-partitioned text indexes:

```rust theme={"languages":{"custom":["languages/helixql.json"]}}
// Declare the text index. Text indexes currently require the partition
// property name to be `tenant_id`.
g().create_text_index_nodes("Doc", "body", Some("tenant_id"))

// Full-text search scoped to a tenant. The tenant value selects the
// partition; the search runs only against that tenant's text index.
g().text_search_nodes(
    "Doc",
    "body",
    "search query string",
    5,
    Some(PropertyValue::from("acme")),
)
```

## Considerations

* **Noisy neighbors.** Tenants share compute and cache, so a high-volume tenant can affect others'
  latency. Monitor per-tenant query volume and apply rate limiting on your infrastructure to mitigate.
* **Shared search semantics.** Secondary indexes remain shared. Tenant-scoped vector and text
  searches require an explicit tenant value for the configured tenant property, and the system
  remains shared infrastructure even when search indexes are partitioned by tenant.

## Stricter Isolation Requirements

For workloads that require namespace-level or infrastructure-level tenant isolation (regulatory
compliance, data residency, or dedicated-resource SLAs), contact us at
[founders@helix-db.com](mailto:founders@helix-db.com) to discuss options.
