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

# Multi-tenancy

> Tenant-isolated indexing and retrieval at scale

Multi-tenancy isolates customer data so each tenant only sees their own documents. VectorDB provides database-specific isolation strategies including namespaces, partitions, payload filters, and tenant-scoped collections.

## Overview

In multi-tenant applications, data from different customers must be strictly isolated to prevent cross-tenant data leakage. Each tenant's queries should only retrieve documents from their own data partition.

<Warning>
  Improper tenant isolation can lead to serious data leakage issues. VectorDB ensures isolation through database-native mechanisms.
</Warning>

## Isolation strategies

Each vector database uses a different approach to tenant isolation:

| Database     | Isolation Strategy                          | Scale               | Description                                                                 |
| ------------ | ------------------------------------------- | ------------------- | --------------------------------------------------------------------------- |
| **Milvus**   | Partition key with filter expressions       | Millions of tenants | Partition key field automatically routes data to tenant-specific partitions |
| **Weaviate** | Native multi-tenancy with per-tenant shards | Enterprise-grade    | Each tenant gets dedicated shard with strong isolation guarantees           |
| **Pinecone** | Namespace-based isolation                   | 100,000+ tenants    | Tenant data stored in separate namespaces within shared index               |
| **Qdrant**   | Payload-based with optimized indexes        | Tiered promotion    | Metadata-based filtering with automatic index promotion for large tenants   |
| **Chroma**   | Tenant and database scoping                 | Flexible            | Collection-per-tenant or database-per-tenant based on scale                 |

## Configuration

Configure multi-tenancy for your chosen database:

<CodeGroup>
  ```yaml Milvus (Partition key) theme={null}
  milvus:
    uri: "http://localhost:19530"
    collection_name: "tenant_documents"
    partition_key: "tenant_id"  # Partition key field
    isolation_strategy: "partition"

  embedder:
    model: "sentence-transformers/all-MiniLM-L6-v2"

  logging:
    level: "INFO"
  ```

  ```yaml Weaviate (Native multi-tenancy) theme={null}
  weaviate:
    cluster_url: "https://your-cluster.weaviate.network"
    api_key: "your-api-key"
    collection_name: "Documents"
    multi_tenancy_enabled: true  # Enable tenant shards

  embedder:
    model: "sentence-transformers/all-MiniLM-L6-v2"
  ```

  ```yaml Pinecone (Namespace isolation) theme={null}
  pinecone:
    api_key: "your-api-key"
    index_name: "multi-tenant-index"
    # Namespace provided per-tenant at runtime

  embedder:
    model: "sentence-transformers/all-MiniLM-L6-v2"
  ```

  ```yaml Qdrant (Payload filtering) theme={null}
  qdrant:
    url: "http://localhost:6333"
    collection_name: "tenant_documents"
    tenant_field: "tenant_id"  # Metadata field for filtering

  embedder:
    model: "sentence-transformers/all-MiniLM-L6-v2"
  ```
</CodeGroup>

## Usage example

<CodeGroup>
  ```python Index for tenant theme={null}
  from vectordb.langchain.multi_tenancy.milvus import (
      MilvusMultiTenancyIndexingPipeline,
  )
  from langchain_core.documents import Document

  pipeline = MilvusMultiTenancyIndexingPipeline(config, tenant_id="acme_corp")

  # Documents automatically isolated to tenant
  documents = [
      Document(
          page_content="Acme Corp product documentation",
          metadata={"source": "docs", "category": "products"}
      ),
      Document(
          page_content="Internal company policies",
          metadata={"source": "internal", "category": "hr"}
      )
  ]

  # Index to tenant partition
  result = pipeline.index(documents)
  print(f"Indexed {result['count']} documents for tenant: acme_corp")
  ```

  ```python Search for tenant theme={null}
  from vectordb.langchain.multi_tenancy.milvus import (
      MilvusMultiTenancySearchPipeline,
  )

  pipeline = MilvusMultiTenancySearchPipeline(config, tenant_id="acme_corp")

  # Search scoped to tenant only
  results = pipeline.search(
      query="product features",
      top_k=10
  )

  # Results only include acme_corp documents
  for doc in results["documents"]:
      print(f"- {doc.page_content[:100]}")
      print(f"  Source: {doc.metadata['source']}")
  ```

  ```python Multi-tenant search with filters theme={null}
  pipeline = MilvusMultiTenancySearchPipeline(config, tenant_id="acme_corp")

  # Combine tenant isolation with metadata filters
  results = pipeline.search(
      query="company policies",
      filters={"category": "hr"},  # Additional filter within tenant
      top_k=5
  )

  print(f"Found {len(results['documents'])} HR documents")
  ```
</CodeGroup>

## Tenant management

### List tenants

```python theme={null}
from vectordb.langchain.multi_tenancy import MilvusMultiTenancyPipeline

pipeline = MilvusMultiTenancyPipeline(config)

# List all active tenants
tenants = pipeline.list_tenants()
print(f"Active tenants: {tenants}")
# Output: ['acme_corp', 'globex_inc', 'initech_llc']
```

### Delete tenant

```python theme={null}
# Delete all data for a tenant
success = pipeline.delete_tenant("acme_corp")

if success:
    print("Tenant data deleted successfully")
else:
    print("Tenant not found or deletion failed")
```

## Framework support

Multi-tenancy pipelines are available for both frameworks:

<CodeGroup>
  ```python LangChain theme={null}
  from vectordb.langchain.multi_tenancy.pinecone import (
      PineconeMultiTenancyIndexingPipeline,
      PineconeMultiTenancySearchPipeline,
  )

  # Create tenant-scoped pipelines
  index_pipeline = PineconeMultiTenancyIndexingPipeline(
      config=config,
      tenant_id="customer_123"
  )

  search_pipeline = PineconeMultiTenancySearchPipeline(
      config=config,
      tenant_id="customer_123"
  )

  # All operations automatically scoped to tenant
  index_pipeline.index(documents)
  results = search_pipeline.search(query, top_k=10)
  ```

  ```python Haystack theme={null}
  from vectordb.haystack.multi_tenancy.pinecone import (
      PineconeMultiTenancyIndexingPipeline,
      PineconeMultiTenancySearchPipeline,
  )

  index_pipeline = PineconeMultiTenancyIndexingPipeline(
      config=config,
      tenant_id="customer_123"
  )

  search_pipeline = PineconeMultiTenancySearchPipeline(
      config=config,
      tenant_id="customer_123"
  )

  index_pipeline.run(documents=documents)
  results = search_pipeline.run(query=query, top_k=10)
  ```
</CodeGroup>

## Isolation guarantees

<AccordionGroup>
  <Accordion title="Milvus partition key isolation">
    **Mechanism**: Partition key field with automatic routing

    **Guarantees**:

    * Data physically separated into tenant-specific partitions
    * Filter expressions automatically scoped to partition
    * Zero cross-tenant data leakage
    * Optimized for millions of tenants

    **Best for**: Applications with 10,000+ tenants requiring strict isolation
  </Accordion>

  <Accordion title="Weaviate native multi-tenancy">
    **Mechanism**: Per-tenant shards with collection-level isolation

    **Guarantees**:

    * Each tenant gets dedicated shard(s)
    * Physical isolation at storage layer
    * Independent tenant lifecycle management
    * Enterprise-grade security boundaries

    **Best for**: SaaS applications with strict compliance requirements
  </Accordion>

  <Accordion title="Pinecone namespace isolation">
    **Mechanism**: Namespace-based logical partitioning

    **Guarantees**:

    * Logical isolation within shared index
    * Query-time namespace filtering
    * Supports 100,000+ namespaces per index
    * Automatic scaling and management

    **Best for**: Multi-tenant SaaS with managed infrastructure preference
  </Accordion>

  <Accordion title="Qdrant payload filtering">
    **Mechanism**: Metadata-based filtering with index optimization

    **Guarantees**:

    * Tenant ID in payload metadata
    * Automatic index creation for tenant field
    * Tiered approach: small tenants share collection, large tenants promoted
    * Efficient filtering with minimal overhead

    **Best for**: Flexible multi-tenant architectures with mixed tenant sizes
  </Accordion>

  <Accordion title="Chroma tenant scoping">
    **Mechanism**: Collection-per-tenant or database-per-tenant

    **Guarantees**:

    * Complete physical isolation
    * Independent collection management
    * Flexible deployment strategies
    * Simple access control

    **Best for**: Development, prototyping, small-scale deployments
  </Accordion>
</AccordionGroup>

## Security best practices

<Steps>
  <Step title="Validate tenant IDs">
    Always validate and sanitize tenant IDs before passing to pipelines. Prevent injection attacks by using allow-lists or UUID validation.

    ```python theme={null}
    import uuid

    def validate_tenant_id(tenant_id: str) -> bool:
        try:
            uuid.UUID(tenant_id)
            return True
        except ValueError:
            return False

    if validate_tenant_id(tenant_id):
        pipeline = MilvusMultiTenancySearchPipeline(config, tenant_id)
    ```
  </Step>

  <Step title="Enforce at application layer">
    Never rely solely on database isolation. Validate tenant access at the application layer before executing queries.

    ```python theme={null}
    def search_for_user(user_id: str, tenant_id: str, query: str):
        # Verify user belongs to tenant
        if not user_belongs_to_tenant(user_id, tenant_id):
            raise PermissionError("Access denied")
        
        # Then execute search
        pipeline = MilvusMultiTenancySearchPipeline(config, tenant_id)
        return pipeline.search(query)
    ```
  </Step>

  <Step title="Audit tenant operations">
    Log all tenant-scoped operations for security auditing and compliance.

    ```python theme={null}
    import logging

    logger = logging.getLogger(__name__)

    result = pipeline.search(query, top_k=10)
    logger.info(
        f"Tenant search: tenant={tenant_id}, query={query}, "
        f"results={len(result['documents'])}"
    )
    ```
  </Step>

  <Step title="Test isolation boundaries">
    Write integration tests that verify cross-tenant data leakage prevention.

    ```python theme={null}
    # Test: tenant A cannot see tenant B's data
    pipeline_a = MilvusMultiTenancySearchPipeline(config, "tenant_a")
    pipeline_b = MilvusMultiTenancySearchPipeline(config, "tenant_b")

    # Index to tenant B
    pipeline_b.index([Document(page_content="Secret data")])

    # Search from tenant A
    results = pipeline_a.search("Secret data")
    assert len(results["documents"]) == 0  # No cross-tenant leakage
    ```
  </Step>
</Steps>

## Performance at scale

### Benchmarks by tenant count

| Tenant Count | Milvus | Weaviate    | Pinecone | Qdrant      | Chroma      |
| ------------ | ------ | ----------- | -------- | ----------- | ----------- |
| 100          | ⚡ Fast | ⚡ Fast      | ⚡ Fast   | ⚡ Fast      | ⚡ Fast      |
| 1,000        | ⚡ Fast | ⚡ Fast      | ⚡ Fast   | ⚡ Fast      | 🔶 Moderate |
| 10,000       | ⚡ Fast | ⚡ Fast      | ⚡ Fast   | ⚡ Fast      | ⚠️ Slow     |
| 100,000+     | ⚡ Fast | ⚡ Fast      | ⚡ Fast   | 🔶 Moderate | ❌ N/A       |
| 1,000,000+   | ⚡ Fast | 🔶 Moderate | ⚡ Fast   | 🔶 Moderate | ❌ N/A       |

<Tip>
  Choose Milvus or Pinecone for applications expecting 10,000+ tenants. Use Weaviate for enterprise compliance needs. Qdrant and Chroma work well for smaller deployments.
</Tip>

## Cost optimization

### Resource sharing strategies

<CodeGroup>
  ```python Shared index (cost-effective) theme={null}
  # Multiple tenants share single index
  # Best for: High tenant count, similar workloads

  pipeline = PineconeMultiTenancySearchPipeline(
      config=config,
      tenant_id=tenant_id  # Namespace isolation
  )

  # Cost: Single index cost / N tenants
  ```

  ```python Dedicated index (high isolation) theme={null}
  # Large tenants get dedicated indexes
  # Best for: Enterprise customers, strict SLAs

  if is_enterprise_tenant(tenant_id):
      config["pinecone"]["index_name"] = f"tenant-{tenant_id}"
      
  pipeline = PineconeMultiTenancySearchPipeline(config, tenant_id)

  # Cost: Full index cost per enterprise tenant
  ```
</CodeGroup>

## Migration between strategies

Migrate from shared to dedicated isolation as tenants grow:

```python theme={null}
def migrate_tenant_to_dedicated(tenant_id: str):
    """Migrate tenant from shared to dedicated index."""
    
    # 1. Create dedicated index
    dedicated_config = config.copy()
    dedicated_config["pinecone"]["index_name"] = f"tenant-{tenant_id}"
    
    # 2. Export from shared index
    shared_pipeline = PineconeMultiTenancySearchPipeline(config, tenant_id)
    documents = shared_pipeline.export_tenant_data()
    
    # 3. Import to dedicated index
    dedicated_pipeline = PineconeMultiTenancyIndexingPipeline(
        dedicated_config, tenant_id
    )
    dedicated_pipeline.index(documents)
    
    # 4. Delete from shared index
    shared_pipeline.delete_tenant(tenant_id)
    
    print(f"Migrated {len(documents)} documents to dedicated index")
```

## Related features

<CardGroup cols={2}>
  <Card title="Namespaces" icon="folder" href="/data/namespaces">
    Logical data partitioning
  </Card>

  <Card title="Metadata filtering" icon="filter" href="/data/metadata-filtering">
    Structured constraints
  </Card>

  <Card title="Cost-optimized RAG" icon="dollar-sign" href="/advanced/cost-optimization">
    Efficient production pipelines
  </Card>

  <Card title="Agentic RAG" icon="robot" href="/advanced/agentic-rag">
    Multi-step retrieval loops
  </Card>
</CardGroup>
