The request fields are now named
database (formerly tenant_id) and collection (formerly sub_tenant_id). The old names and the old /tenants routes remain fully supported as deprecated aliases, so existing integrations keep working without any changes — however, we recommend using the latest conventions. See Migrating from tenant_id and sub_tenant_id for the full compatibility contract.1. What it is
HydraDB scopes data using two identifiers:database- the top-level scoping identifier. Use it for customers, environments, or other primary data boundaries.collection- an optional scoping identifier within a database. Use it for users, workspaces, teams, or other logical partitions.
database. When collection is provided, it further narrows the scope for that operation. If you omit collection, HydraDB uses the database’s default collection.
Use the same scoping values consistently across writes and reads. If you write data with one collection and later query with a different one, that data may not appear in the query results.
2. When to use each
Two practical rules:
- Use a separate database whenever data must not mix across customers or environments.
- Use a collection for logical partitions inside a database, such as users, workspaces, teams, or projects.
collection as a substitute for separate production and staging databases. Environments should usually be separated at the database level.
3. Recommended patterns
B2C application
Use one database for the application or customer account, and use each end-user as a collection.- Write user Memories with
collection = user_id. - Query user Memories with the same
collection. - Keep shared Knowledge outside the user-specific scope.
B2B SaaS
Use one database per customer organization. Usecollection for the workspace, team, project, or user scope inside that customer.
- Customer-level Knowledge uses the customer
database. - Workspace-specific data uses a workspace
collection. - User-specific Memories use a user-level
collection.
Shared Knowledge + user personalization
For personalized answers grounded in shared Knowledge, use thetype parameter on POST /query:
type: "knowledge"retrieves shared Knowledge (Knowledge vector store,vectorstore_status.knowledge).type: "memory"retrieves user-specific Memories (Memories vector store,vectorstore_status.memories).type: "all"runs both in parallel and returns one merged, re-ranked result set - usually what you want for personalized answers.
POST /query twice (once with type: "knowledge", once with type: "memory") and combine in your application.
4. How scoping works
Writes
Writes includedatabase, and may include collection.
Use collection when the data belongs to a specific user, workspace, team, or other logical partition. Omit it when you intentionally want the data written to the database’s default collection.
Examples:
- A memory about John’s preferences should be written with John’s
collection. - Workspace-specific runbooks should be written with that workspace’s
collection. - Broadly shared Knowledge should use the same scope you plan to use when querying it.
Reads
Query requests includedatabase, and may include collection. If collection is omitted, query uses the database’s default collection.
Use the same scoping values on query that you used when writing the data. A query request with one collection should not be expected to retrieve data written under a different collection.
If your application needs to combine data from multiple scopes, prefer one query call with collections unless you need separate response formatting or client-side treatment per scope.
Use collection for partitioning data. Use metadata_filters for narrowing results within that scope.
Memories and Knowledge
Memories and Knowledge live in separate stores, both reached throughPOST /query:
type: "memory"retrieves Memories (user-scoped, personal).type: "knowledge"retrieves Knowledge (shared documents and app sources).type: "all"retrieves both in one call.
POST /query with type: "all" and the user’s collection. HydraDB runs both stores in parallel and merges results. Use two separate calls only when you need to format the two streams differently in your LLM prompt.
5. Minimal working example
The example below shows a common personalized-answer flow: write a user Memory with a singlecollection, then query Knowledge and Memories together with collections.
6. Common mistakes
Mismatchedcollection between write and read.
Data written under one collection should not be expected to surface when queried under another. Use the same collection consistently for the same logical scope.
Sharing a database across environments.
Do not use one database for both production and staging. Create separate databases for separate environments.
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.
Assuming query automatically searches every collection.
A query call uses the scope you provide. If your application needs data from multiple scopes, pass collections as a list or weighted object.
Writing shared Knowledge under a user scope by accident.
If broadly shared Knowledge is written with a user-specific collection, it may not appear where other users expect it. Choose the write scope based on where the content should be queried later.
Using metadata filters as a substitute for collections.
Metadata filters narrow results inside a scope. They are not a replacement for choosing the right database and collection.
Using unstable identifiers.
Avoid display names, emails that may change, or user-provided labels as long-term scope identifiers. Prefer stable internal IDs such as user_123, workspace_42, or org_acme.
7. Migrating from the legacy tenant and sub-tenant fields
database/collection are the canonical v2 names for what were historically called tenant_id/sub_tenant_id. The rename is user-facing only: internally HydraDB still uses the historical names, so nothing about your data changes. The old names remain accepted forever; migration is optional and non-breaking.
Backward compatibility is total across every surface:
Both prefixes dispatch to the same handlers, and the legacy fields are accepted in the query string, JSON body, and multipart form. An existing integration that uses only the old names is a pure no-op and behaves exactly as before.
On
/query, collections is the canonical way to scope to one or more collections (send a list, or an object mapping collection ID to a relative ranking weight). sub_tenant_ids remains accepted as its deprecated alias, and the singular sub_tenant_id still works too. See Query.
Deprecation signals
When a request uses a legacy route or a legacy field, HydraDB adds a non-breaking migration nudge (never an error, and the status code is unchanged):Deprecation: trueresponse header, plus aWarningheader carrying the migration message.meta.deprecation: a list of structured notices in the response envelope’smetaobject (for endpoints that return the envelope). Each entry carriesdeprecated, a human-readablemessage, anddeprecated_since(e.g."2.0.1"); field-level notices (such assub_tenant_ids→collections) also includedeprecated_fieldandpreferred_field, while route-level notices omit them. Fully-migrated requests omit the list entirely.
/databases routes, the header and meta.deprecation disappear.
Sending both names
If you send both a canonical field and its deprecated alias:- Same value (for example
databaseandtenant_idboth"acme"): accepted. HydraDB uses the canonical value. - Different values (for example
database: "acme"andtenant_id: "other"): rejected with400, since the two names refer to the same thing and must agree. Send only one. The same rule applies tocollection/sub_tenant_idand tocollections/sub_tenant_idson/query.
Related
- Memories - user-scoped context
- Knowledge - shared document context
- Query - how scoping is applied at query time
- How to Use API Results - merging query results into a prompt
- Create Database - defining databases and their metadata schema