# How to Use the Workspace Parameter in LightRAG for Multi-Tenant RAG Application Isolation

> Learn how the LightRAG workspace parameter isolates tenant data across KV, vector, and graph stores. Secure multi-tenant RAG applications with this essential feature.

- Repository: [✨Data Intelligence Lab@HKU✨/LightRAG](https://github.com/HKUDS/LightRAG)
- Tags: how-to-guide
- Published: 2026-03-23

---

**The `workspace` parameter in LightRAG isolates tenant data by prefixing a workspace identifier to every internal namespace, ensuring that KV stores, vector stores, and graph databases remain separate within a single LightRAG instance.**

The LightRAG library (HKUDS/LightRAG) provides a powerful `workspace` parameter that enables multi-tenant architectures without deploying separate infrastructure. By attaching a tenant-specific string to all storage namespaces, you can serve multiple isolated knowledge bases from one process while guaranteeing data separation and concurrent access safety.

## How Workspace Isolation Works in LightRAG

The workspace mechanism operates at the storage layer through namespace prefixing. In [`lightrag/kg/shared_storage.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/kg/shared_storage.py), the `get_final_namespace()` function concatenates the workspace identifier with the base namespace:

```python

# lightrag/kg/shared_storage.py

def get_final_namespace(namespace: str, workspace: str | None = None):
    if workspace is None:
        workspace = _default_workspace
    final_namespace = f"{workspace}:{namespace}" if workspace else f"{namespace}"
    return final_namespace

```

When you initialize `LightRAG(workspace="tenant_a")`, the system transforms global keys like `full_docs` into `tenant_a:full_docs`. This prefixing applies consistently across **KV storage**, **vector storage**, **graph storage**, and **pipeline status** tracking, creating logical isolation without physical database separation.

## Configuring the Workspace Parameter

LightRAG supports three distinct patterns for workspace configuration, allowing flexibility across different architectural requirements.

### Instance-Level Workspace Configuration

Pass the `workspace` argument directly to the `LightRAG` constructor in [`lightrag/lightrag.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/lightrag.py). This binds the instance to a specific tenant namespace for its entire lifecycle:

```python
from lightrag import LightRAG

rag = LightRAG(
    working_dir="./data",
    workspace="tenant_a",  # All operations scoped to tenant_a

    llm_model_func=my_llm_func,
    embedding_func=my_embedding_func
)

```

### Global Default Workspace

For applications managing multiple LightRAG instances programmatically, use `set_default_workspace()` from [`lightrag/kg/shared_storage.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/kg/shared_storage.py). This module-level setting applies to all subsequent storage operations that omit an explicit workspace:

```python
from lightrag.kg.shared_storage import set_default_workspace

set_default_workspace("tenant_xyz")

# Subsequent storage calls automatically use "tenant_xyz" prefix

```

### Per-Call Overrides

Low-level storage functions accept an explicit `workspace` parameter that overrides the global default for individual operations. Functions like `get_namespace_data()`, `get_namespace_lock()`, and `initialize_pipeline_status()` support this pattern:

```python
from lightrag.kg.shared_storage import get_namespace_lock

async with get_namespace_lock("pipeline_status", workspace="override_tenant") as lock:
    # Lock acquired specifically for "override_tenant:pipeline_status"

    pass

```

## Multi-Tenant Isolation Mechanisms

The workspace parameter activates several safety mechanisms that prevent cross-tenant data leakage while maintaining performance.

### Namespaced Storage Access

Every storage implementation receives fully-qualified namespace identifiers. For example, `JsonKVStorage` instances created for different workspaces operate on distinct key ranges. The workspace `"finance"` accesses keys prefixed with `"finance:"`, while `"hr"` accesses keys prefixed with `"hr:"`. This applies uniformly to document storage (`full_docs`), chunk storage (`text_chunks`), and relationship mappings.

### Lock Granularity and Concurrency

The `get_namespace_lock()` function in [`lightrag/kg/shared_storage.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/kg/shared_storage.py) creates async locks scoped to specific `workspace:namespace` pairs:

```python
def get_namespace_lock(namespace: str, workspace: str | None = None, enable_logging: bool = False):
    return NamespaceLock(namespace, workspace, enable_logging)

```

This design allows **concurrent operations** across tenants. Tenant A can acquire a lock on `pipeline_status` while Tenant B simultaneously locks the same logical namespace, because the underlying keys (`tenant_a:pipeline_status` and `tenant_b:pipeline_status`) differ.

### Pipeline Status Isolation

Each workspace maintains independent pipeline processing state. The `initialize_pipeline_status()` function creates separate tracking objects per workspace, preventing status conflicts when multiple tenants ingest documents simultaneously. The test suite in [`tests/test_workspace_isolation.py`](https://github.com/HKUDS/LightRAG/blob/main/tests/test_workspace_isolation.py) validates this behavior by verifying that workspace-specific pipeline statuses do not interfere.

## Practical Implementation Examples

### Multiple Tenant Instances

The example file [`examples/lightrag_gemini_workspace_demo.py`](https://github.com/HKUDS/LightRAG/blob/main/examples/lightrag_gemini_workspace_demo.py) demonstrates creating isolated workspaces for different document collections:

```python
async def initialize_rag(workspace_name):
    return LightRAG(
        working_dir=f"./{workspace_name}",
        workspace=workspace_name,
        llm_model_func=gemini_call,
        embedding_func=embedding_func
    )

# Create isolated instances

rag_books = await initialize_rag("rag_workspace_book")
rag_hr = await initialize_rag("rag_workspace_hr")

# Insert data into separate tenants

await rag_books.ainsert(book_content)
await rag_hr.ainsert(hr_content)

# Queries return tenant-specific results

book_result = await rag_books.aquery("Main themes?")
hr_result = await rag_hr.aquery("Leave policy?")

```

### Global Default Pattern

When managing numerous storage operations outside the main LightRAG class, set a global default to avoid repetitive parameter passing:

```python
from lightrag.kg.shared_storage import set_default_workspace, get_namespace_data

set_default_workspace("tenant_xyz")

# All subsequent calls use "tenant_xyz" automatically

kv_store = await get_namespace_data("full_docs")

# Effectively accesses "tenant_xyz:full_docs"

```

### Direct Namespace Manipulation

For advanced use cases requiring direct storage access:

```python
from lightrag.kg.shared_storage import get_namespace_data

kv_store = await get_namespace_data("full_docs", workspace="tenant_123")
kv_store["doc_1"] = {"content": "Confidential data"}
await kv_store.save()

```

## Summary

- The **workspace parameter** prefixes tenant identifiers to all storage namespaces in LightRAG, creating logical isolation within a single instance.
- **Three configuration modes** exist: instance-level constructor arguments, global defaults via `set_default_workspace()`, and per-call overrides.
- **Lock isolation** prevents cross-tenant blocking while allowing concurrent access to the same logical namespaces.
- **Pipeline statuses** are fully isolated per workspace, enabling simultaneous document processing across tenants.
- No separate databases or directories are required—workspaces operate within the same physical storage backend using key prefixes.

## Frequently Asked Questions

### What happens if I don't specify a workspace?

If the workspace parameter is omitted or set to an empty string, LightRAG operates in the global namespace without any prefix. According to [`lightrag/kg/shared_storage.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/kg/shared_storage.py), the `get_final_namespace()` function returns the original namespace unchanged when the workspace value is falsy, maintaining backward compatibility with non-multi-tenant deployments.

### Can multiple workspaces share the same working directory?

Yes. Workspaces are logical constructs that modify internal namespace keys rather than file system paths. Both `"tenant_a"` and `"tenant_b"` can use the same `working_dir` configuration while maintaining complete data isolation through prefixed keys. However, for file-based storage backends, ensure your backup and security policies account for this co-location if physical separation is required for compliance.

### How does workspace isolation affect memory and performance?

The workspace parameter adds minimal overhead—only string concatenation during namespace resolution. Memory usage scales with the number of active tenant storages cached in memory, not with the total workspace count. Locks remain efficient because they use distinct keys per workspace, preventing contention between tenants while avoiding the overhead of separate database connections.

### Is workspace isolation compatible with async and multiprocessing modes?

Yes. The `get_namespace_lock()` implementation in [`lightrag/kg/shared_storage.py`](https://github.com/HKUDS/LightRAG/blob/main/lightrag/kg/shared_storage.py) provides unified locking that works across both asyncio coroutines and multiprocessing environments. Each workspace-namespace combination maintains its own lock state, ensuring safety regardless of whether LightRAG runs in single-process async mode or distributed across multiple processes.