Multi-tenant RAG

Every customer’s data in its own namespace, not behind a filter.

For SaaS copilots and assistants: your backend writes each customer’s documents to their namespace, and the copilot searches with a key that reaches theirs alone. Exact, regex, filtered and vector retrieval; idle customers cost only their bytes.

0.8mswarm query p50, on real S3
10,000namespaces on one server, measured
806Ban idle namespace in object storage
$0compute for an idle customer

From recorded runs, with how each was measured, on the benchmarks page.

A namespace per customer

Made by its first write, with no limit on how many on pro. A customer’s data is one prefix in object storage: easy to reason about, count, export or delete.

The key is the boundary

Your copilot calls SkimmerDB with a key that reaches one workspace. A bug, a missing filter or a prompt injection can’t widen that: the rest answer 404.

Recall that matches how people ask

Vectors for meaning, literal and regex search for names and numbers, metadata filters for source, owner and dates, all in one query. Exact counts when a user asks “how many”.

A shared index with a filter, or a namespace each

One shared indexSkimmerDB
Where a customer’s data livesOne shared index, every row tagged with tenant_idIts own namespace
What keeps customers apartA filter your code must never forgetThe key: other namespaces don’t exist for it
A customer leavesDelete by filter, hope nothing was missedDelete the namespace
A big customer arrivesThe shared index grows; everyone’s queries scan moreIts namespace grows; the others don’t change
Idle customersKept in the same hot index as active onesBytes in S3, no compute
Exact matches (ids, codes, names)Often a second system next to the vector indexThe same query, the same copy

Sync from your backend, retrieve from the copilot

Documents are an id, text, metadata and an embedding if you have one. Writing an id again replaces it, so syncing a changed document is one write.

sync a workspace
# your backend: one namespace per customer workspace
W=https://api.skimmerdb.com/v1/namespaces/ws-4812

curl $W/docs -H "Authorization: Bearer $ADMIN" -d '{
  "docs": [{"id": "doc-91#3",
    "text": "Q3 renewal terms for Globex: 12% uplift, net 45",
    "meta": {"source": "drive", "owner": "maria", "updated": 20261012},
    "vector": [0.12, -0.03, ...]}]}'

# a customer leaves: everything they stored goes with one call
curl -X DELETE $W -H "Authorization: Bearer $ADMIN"
retrieve for a user
# the copilot, for a user of workspace 4812
curl $W/search -H "Authorization: Bearer $WS_KEY" -d '{
  "vector": [0.04, 0.17, ...], "q": "globex",
  "filter": {"source": ["drive", "crm"]}, "limit": 8}'

# "how many open deals mention net 60?" counted, not guessed
curl $W/count -H "Authorization: Bearer $WS_KEY" -d '{
  "q": "net 60", "filter": {"source": "crm", "stage": {"ne": "closed"}}}'

One key per customer

Make a key when a workspace is created and hand it to the copilot that serves it. Change its reach or caps at once; revoke it at once.

  • Scoped. Read, write or admin, limited to names or a prefix like ws-4812-*.
  • Capped. Requests a second, queries and writes a billing period.
  • Accounted. Every answer reports its latency, object-store reads and CPU.
a key for one workspace
# a key per workspace, made when the workspace is
curl https://api.skimmerdb.com/v1/keys -H "Authorization: Bearer $ADMIN" -d '{
  "name": "ws-4812 copilot", "scope": "read",
  "namespaces": ["ws-4812", "ws-4812-*"],
  "cap_queries": 200000}'

Questions

What is multi-tenant RAG?

Retrieval-augmented generation for an app with many customers: each customer’s copilot or assistant must retrieve only from that customer’s documents. The usual build is one vector index with a tenant_id filter on every query; SkimmerDB gives each customer a namespace of its own and keys that can only reach it.

Why not one index with a tenant_id filter?

It works until a query forgets the filter, and then one customer sees another’s data. With a namespace per customer and a key per namespace, isolation doesn’t depend on every code path being right. Deleting a customer is deleting a namespace, and a large customer doesn’t make everyone else’s index bigger.

How many namespaces can I have?

Unlimited on pro; the free plan allows 1,000. An idle namespace is under a kilobyte of bookkeeping plus its documents in object storage, and runs no compute, so a long tail of quiet customers costs what they store.

Who writes the data, my backend or the agent?

Usually your backend, through the REST API, the Python and TypeScript clients, or bulk imports of CSV, NDJSON and Parquet. The copilot only needs a read key. Agents that should save things (notes, memories) can get a write key limited to their namespace.

Can I see what each customer uses?

Listing namespaces gives each one’s stored bytes and the documents and bytes written to it, and every query answer reports its latency, cache temperature, object-store reads and CPU, so you can attribute cost per customer. Key caps limit what each customer’s key can do in a billing period.

What does a quiet customer cost?

Only its storage: $0.10 per GB-month on pro, and the free plan includes 1 GB. Its first query after a long sleep reads from object storage in a round trip or two, then it’s warm.

Give every customer their own index

Free up to 1 GB stored and 100k queries a month. No card to start.