← Back to all posts
May 15, 2026TechRevati

Multi-tenant RAG: lessons from 17 phases of EinCoreRAG

How PostgreSQL RLS and per-tenant Qdrant collections isolate data in enterprise AI environments.

  • architecture
  • security

Multi-tenant RAG: lessons from 17 phases of EinCoreRAG

When building enterprise AI systems, the first question from any CISO is: “How do you guarantee my data won’t leak to another tenant?”

In EinCoreRAG, we tackled this by enforcing isolation at two critical layers: the relational database and the vector database.

1. Relational Layer: PostgreSQL Row-Level Security (RLS)

Application-layer authorization is brittle. A single missing WHERE tenant_id = ? clause can expose sensitive data.

Instead, we pushed isolation down to the database engine using PostgreSQL RLS:

ALTER TABLE documents ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation_policy ON documents
    USING (tenant_id = current_setting('app.current_tenant_id'));

Our API layer sets the app.current_tenant_id variable at the start of every request transaction. This guarantees that all queries naturally filter out data belonging to other tenants.

2. Vector Layer: Qdrant Collections

Vector databases pose a different challenge. Initially, we considered using a single shared collection with a tenant_id payload filter.

However, we moved to per-tenant collections in Qdrant for three reasons:

  1. True Isolation: A compromised or misconfigured query cannot cross collection boundaries.
  2. Performance: HNSW indices perform better when they don't have to navigate massive, diverse graphs.
  3. Data Residency: Specific tenants can have their collections routed to specific geographic regions or dedicated clusters.

The Result

The combination of RLS and separated vector collections creates a "fail-closed" architecture. Even if the application logic contains a flaw, the data engines refuse to serve cross-tenant records.

This post has been redacted by our automated security pipeline to remove internal topology details.