Prompt
I’m building an app with tenant-level filtering on vector search
Latest observation
Oct 10, 2026
OpenAI APIWeb search: off
Got it — tenant-level filtering for vector search is a common multi-tenant design pattern.
At a high level, you want every vector query to be constrained by a tenant identifier so one tenant can never retrieve another tenant’s embeddings, even if similarity is high.
Typical approach
Store these fields alongside each embedding:
tenant_iddocument_idorrecord_idembedding- any metadata you want to filter on
Then enforce:
- Write-time isolation: every inserted vector is tagged with the correct
tenant_id - Query-time filtering: every similarity search includes
tenant_id = current_tenant - Authorization layer: the app never accepts arbitrary tenant filters from the client without validation
Common architectures
1. Single shared index / table
All tenants share the same vector store, but each record has tenant_id.
Pros:
- simpler ops
- cheaper
- easier to scale initially
Cons:
- must be careful with access control
- some databases/vector engines may have filter performance concerns at scale
2. Separate index per tenant
Each tenant gets its own vector index or namespace.
Pros:
- stronger isolation
- easier mental model
- can reduce accidental leakage
Cons:
- operational overhead
- poor fit if you have many tenants
- harder to manage index explosion
3. Hybrid
Use namespaces or partitions for large tenants, shared storage for small tenants.
Good when:
- you have very uneven tenant sizes
- you need strong performance for enterprise tenants
Important security rule
Never rely only on the vector DB filter if the tenant ID comes from the client.
Instead:
- derive tenant context from authenticated session / JWT / API key
- inject tenant filter server-side
- ideally use database-level policies or row-level security where possible
Query pattern
Example logic:
- Authenticate request
- Resolve
tenant_id - Embed query
- Search vectors with:
- similarity constraints
tenant_id = resolved_tenant_id- optional metadata filters like
doc_type,status,created_at
Things to watch out for
- Approximate nearest neighbor leakage: make sure the filter is applied correctly, not after retrieval in app code only
- Filter selectivity: if tenant filters are sparse, some engines may degrade
- Cache keys: include
tenant_idin cache keys - Deletes/updates: ensure tenant-scoped lifecycle operations
- Testing: add tests for cross-tenant isolation explicitly
Example pseudo-query
SELECT *
FROM embeddings
WHERE tenant_id = :tenant_id
ORDER BY embedding <-> :query_embedding
LIMIT 10;
Or with metadata filters:
SELECT *
FROM embeddings
WHERE tenant_id = :tenant_id
AND status = 'active'
ORDER BY embedding <-> :query_embedding
LIMIT 10;
Best practice recommendation
For most SaaS apps:
- start with a shared index + required tenant filter
- enforce tenant identity in the backend
- add per-tenant namespaces only for large or premium tenants if needed
If you want, I can help you design:
- a schema for Postgres + pgvector,
- a Pinecone/Qdrant/Weaviate tenant-filtering setup, or
- an end-to-end secure request flow for your app.