How to Use the Workspace Parameter in LightRAG for Multi-Tenant RAG Application Isolation
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, the get_final_namespace() function concatenates the workspace identifier with the base namespace:
# 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. This binds the instance to a specific tenant namespace for its entire lifecycle:
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. This module-level setting applies to all subsequent storage operations that omit an explicit workspace:
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:
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 creates async locks scoped to specific workspace:namespace pairs:
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 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 demonstrates creating isolated workspaces for different document collections:
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:
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:
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, 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →