Skip to main content
HydraDB scopes every write and every read with two fields: database, a separate workspace for a customer or an environment, and collection, an optional group inside a database. Most products need one database and one collection. Your backend sets both on every request; the end user never chooses them. In this guide:
  1. Choose how to scope your data: one collection for a company brain, and when to split.
  2. Write and read with the same scope: one write and one read that name the same collection.
  3. How writes and reads scope: the default collection, reading several collections, and deleting one.
  4. Migrate from the legacy tenant and sub-tenant fields: tenant_id, sub_tenant_id, and the deprecation signals.
  5. Common mistakes and related pages.

1. Choose how to scope your data

Pick the scope by what must never meet in one search:

Company brain

Put everything in one collection: connect all your connectors and ingest all your files and app sources there, so one query searches across all of it. When some results must stay out of reach for some people, keep the single collection and isolate inside it. Put a team, region, or user id in metadata and filter on it. Let access control, captured from the source app’s permissions or set by you, decide who may retrieve each document. HydraDB enforces both inside one search.

B2C application

Use one database for the application. Keep shared knowledge in one collection, and give each end user a collection for their memories, for example collection = "user_123". Write each user’s preferences and conversation history with that collection, and query with the same one.

B2B SaaS

Use one database per customer organization, for example database = "acme_corp". Inside it, keep the organization’s knowledge in one collection and isolate teams with metadata filters and access control. Give each user a collection only for their memories.

Shared knowledge plus personal memories

For answers grounded in shared knowledge and personalized with the user’s memories, send type: "all" on POST /query. It reads both from the same collections and returns one ranked list, so name the knowledge collection and the user’s with collections: ["company_docs", "user_123"]. Every listed collection must already exist, and the list holds up to 100. When your prompt needs the two formatted differently, call POST /query twice, once with type: "knowledge" and once with type: "memory".

2. Write and read with the same scope

This example saves a memory for user_123 and then runs a search for the same user. Both requests name the database acme_corp and the collection user_123. That is the whole mechanism: data written under a collection is read back only by requests that name that collection.
Set up your SDK client before running the Python or TypeScript example.
Wait for GET /context/status to report completed for the returned memory id in user_123, then run the query.

What each property means

Use stable internal IDs for both fields, such as user_123, workspace_42, or org_acme. Display names, emails, and user-typed labels change, and a changed scope name orphans the data written under the old one.

3. How writes and reads scope

Every write and read names a database, and may name a collection. Writes: Send the collection you will query the data from. Omit it to use the database’s default collection. John’s memories go in John’s collection; shared knowledge goes in the shared one. Reads: A query that names one collection reads only that collection. It does not read the default collection or any other collection. To read several at once, send collections as a list, or as an object that maps each collection to a relative ranking weight, as in {"company_docs": 1.5, "user_123": 0.8}. Deleting a collection: DELETE /databases/collections permanently removes one collection and everything in it. The parent database and its other collections stay. Confirm the name with List Collections first. On the dashboard, open a database to see its collections and delete from the list.

4. Migrate from the legacy tenant and sub-tenant fields

database and collection are the current names for the fields that were called tenant_id and sub_tenant_id. The rename is user-facing only. Nothing about your stored data changes, the old names still work as deprecated aliases, and migration is optional and non-breaking. Both names work on every surface: Both route prefixes use the same handlers. Legacy fields are accepted in the query string, the JSON body, and the multipart form. The singular sub_tenant_id still works on /query too. See Query.

Deprecation signals

When a request uses a legacy route or a legacy field, HydraDB adds a migration nudge. It is never an error, and the status code is unchanged:
  • Response headers: Deprecation: true, plus a Warning header carrying the migration message.
  • meta.deprecation: a list of notices in the response envelope’s meta object, on endpoints that return the envelope. Each entry carries deprecated, a readable message, and deprecated_since ("2.0.1"). Field-level notices, such as sub_tenant_ids to collections, also include deprecated_field and preferred_field; route-level notices omit them.
Use these signals to find and retire legacy usage. Once you send only the current names on the /databases routes, the header and meta.deprecation disappear.

Sending both names

If you send a current field and its deprecated alias together:
  • Same value: for example database and tenant_id both "acme". Accepted. HydraDB uses the current field.
  • Different values: for example database: "acme" and tenant_id: "other". Rejected with 400, because the two names refer to the same thing and must agree. Send only one. The same rule applies to collection and sub_tenant_id, and to collections and sub_tenant_ids on /query.

Common mistakes

Mismatched collection between write and read: Data written under one collection does not surface when queried under another. Use the same collection for the same logical scope on every call. Sharing a database across environments: Do not use one database for both production and staging. Create a database per environment. Confusing database with collection: Use database for primary boundaries such as customers or environments. Use collection for partitions inside a database, such as users or workspaces. Writing shared knowledge under a user scope by accident: Knowledge written with one user’s collection is invisible to every other user. Choose the write scope from where it should be queried later.