mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-11 03:37:56 +00:00
Rewrites 339 TypeScript calls across 50 pages from the rc.5 `method({ namespace, body })` form to the shipped `method(namespace, { ... })` form, and aligns field names with the live v5 spec: `attach` to `include`, `authUrl` to `authorization`, `lastSync` to `latestRun`, `deletedCount` to `count`, and the paginated `namespaces.list()`.
Renames container tags to namespaces across concepts, connectors, integrations and snippets. The namespace pages keep container tag in the description, search keywords and a rename note so old searches still land, and the v3 reference page points at v5.
The migration guide's SDK table now covers both 5.0.0 SDKs, and the SDK integration page uses the real client options (`baseUrl`, `timeoutInSeconds`, `maxRetries`) and error classes.
125 lines
5.3 KiB
Text
125 lines
5.3 KiB
Text
---
|
|
title: "Multi-tenancy overview"
|
|
sidebarTitle: "Overview"
|
|
description: "How Supermemory isolates and organizes memories across users, tenants, and projects"
|
|
icon: "/icons/hugeicons/user-multiple.svg"
|
|
---
|
|
|
|
Most apps built on Supermemory serve more than one user, customer, or tenant out of a single Supermemory organization. Multi-tenancy is how you keep those memories apart — so User A's data is never visible to User B, and so you can still slice and query within a user's own data by things like category, status, or date.
|
|
|
|
Supermemory gives you two complementary tools for this:
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Namespaces" icon="/icons/hugeicons/folder-01.svg" href="/concepts/container-tags">
|
|
**Isolation.** A namespace is a hard boundary. Memories in one namespace are never returned by a search scoped to another namespace.
|
|
</Card>
|
|
<Card title="Metadata filtering" icon="/icons/hugeicons/database-01.svg" href="/concepts/filtering">
|
|
**Organization.** Metadata is a set of custom key/value properties on a memory that you filter by — category, priority, date, participants, anything you define.
|
|
</Card>
|
|
</CardGroup>
|
|
|
|
They solve different problems, and most production apps use both together.
|
|
|
|
---
|
|
|
|
## Why two mechanisms
|
|
|
|
It's tempting to reach for one tool and make it do everything, but namespaces and metadata aren't interchangeable — they answer different questions.
|
|
|
|
| Question | Answer |
|
|
|----------|--------|
|
|
| "Which tenant does this memory belong to?" | **Namespace** |
|
|
| "Within this tenant's memories, which ones match `status: open`?" | **Metadata filter** |
|
|
| "Can this API key even see tenant X's data?" | **Namespace** (enforced as an access boundary) |
|
|
| "Find memories tagged `engineering` created after March" | **Metadata filter** |
|
|
|
|
A namespace decides **whether a memory is reachable at all** for a given request. Metadata decides **which of the reachable memories match**. Filtering never crosses a namespace boundary — you can't use metadata to peek into another tenant's namespace.
|
|
|
|
---
|
|
|
|
## How they work together
|
|
|
|
A typical multi-tenant write scopes the memory to a tenant with a namespace, then attaches metadata for finer-grained querying later:
|
|
|
|
```typescript
|
|
await supermemory.add("org_acme", { // isolates to the "acme" tenant
|
|
content: "Customer requested a refund for order #4821",
|
|
metadata: {
|
|
category: "support",
|
|
status: "open",
|
|
priority: "high",
|
|
},
|
|
});
|
|
```
|
|
|
|
And a search combines both: the namespace restricts *which tenant's data* is in scope, and the filter narrows down *which memories within that tenant* come back:
|
|
|
|
```typescript
|
|
const results = await supermemory.search("org_acme", {
|
|
query: "refund request",
|
|
filter: {
|
|
operator: "and",
|
|
operands: [
|
|
{ field: "category", operator: "eq", value: "support" },
|
|
{ field: "status", operator: "eq", value: "open" },
|
|
],
|
|
},
|
|
searchMode: "chunks",
|
|
});
|
|
```
|
|
|
|
<Note>
|
|
The namespace is **required** on every call (it is part of the URL) and validated as an access boundary. Metadata filters are **optional** — a search with just `namespace` and no `filter` still only returns that tenant's memories.
|
|
</Note>
|
|
|
|
---
|
|
|
|
## Choosing your boundary
|
|
|
|
The namespace is the layer that should map to your actual tenancy model — pick the level that matches what "one isolated space" means in your app:
|
|
|
|
| Pattern | Example | Use case |
|
|
|---------|---------|----------|
|
|
| Per-user | `user_{userId}` | Consumer app, personal memory per user |
|
|
| Per-tenant/org | `org_{orgId}` | B2B SaaS, one namespace per customer org |
|
|
| Hierarchical | `org:{orgId}:user:{userId}` | Multi-level — isolate by org, and optionally drill into a user within it |
|
|
| Per-project | `project_{projectId}` | Workspace- or project-scoped content |
|
|
|
|
The simplest form is one namespace per user, derived from an ID you already have:
|
|
|
|
```typescript
|
|
await supermemory.add(userId, { // one namespace per user
|
|
content: "User prefers morning workouts",
|
|
});
|
|
|
|
const results = await supermemory.search(userId, {
|
|
query: "workout preferences",
|
|
});
|
|
```
|
|
|
|
Everything *within* that boundary — categories, statuses, dates, custom fields — is metadata, not a new namespace. Don't create a new namespace for every property you want to filter on; that's what metadata is for.
|
|
|
|
---
|
|
|
|
## Access control
|
|
|
|
Namespaces aren't just organizational — they're enforced as an authorization boundary. API keys and org members can be restricted to specific namespaces, so a request for a namespace outside the caller's allowed set is rejected with `403 Forbidden` rather than silently filtered. See [Namespaces → Access control](/concepts/container-tags#access-control) for the details.
|
|
|
|
---
|
|
|
|
## Next steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Examples" icon="/icons/hugeicons/check-list.svg" href="/concepts/multi-tenancy-examples">
|
|
Personal agents, company agents, email assistants, and support platforms.
|
|
</Card>
|
|
<Card title="Namespaces" icon="/icons/hugeicons/folder-01.svg" href="/concepts/container-tags">
|
|
How isolation works, naming rules, and access control.
|
|
</Card>
|
|
<Card title="Organizing & Filtering" icon="/icons/hugeicons/filter.svg" href="/concepts/filtering">
|
|
Metadata filter operators, combining `and`/`or`, and query limits.
|
|
</Card>
|
|
<Card title="Scoped API keys" icon="/icons/hugeicons/key-01.svg" href="/authentication#scoped-api-keys">
|
|
Mint keys that can only touch one namespace.
|
|
</Card>
|
|
</CardGroup>
|