Choose a Multitenancy Design
Choose a design from the number of tenants, their relative sizes, and their isolation requirements. Start with payload-based partitioning when many tenants share the same collection configuration. Use dedicated shards or collections when a tenant needs different capacity or configuration.
| Workload or constraint | Starting design | Main trade-off |
|---|---|---|
| Many small tenants with similar data and vector configuration. | One collection with a tenant payload field and index. | Tenants share collection resources and configuration. |
| A few large tenants and many small tenants. | Tiered multitenancy with shared and dedicated shards. | You must plan shard capacity and tenant promotion. |
| A small number of tenants need separate collection configuration or collection-level permissions. | Separate collections. | Each collection adds resource and operational overhead. |
| A tenant’s data must reside on specific nodes. | Custom shard keys and explicit shard placement. | You must manage shard placement and capacity. |
These choices can be combined. For example, a custom shard can contain several tenants separated by payload filters.
Keep Small Tenants in a Shared Collection
Add a tenant identifier, such as group_id, to every point’s payload. Create a keyword index with is_tenant: true on that field. Qdrant can then organize points from the same tenant together. The flag is available from Qdrant 1.11.
PUT /collections/{collection_name}/index
{
"field_name": "group_id",
"field_schema": {
"type": "keyword",
"is_tenant": true
}
}
client.create_payload_index(
collection_name="{collection_name}",
field_name="group_id",
field_schema=models.KeywordIndexParams(
type=models.KeywordIndexType.KEYWORD,
is_tenant=True,
),
)
client.createPayloadIndex("{collection_name}", {
field_name: "group_id",
field_schema: {
type: "keyword",
is_tenant: true,
},
});
use qdrant_client::qdrant::{
CreateFieldIndexCollectionBuilder,
KeywordIndexParamsBuilder,
FieldType
};
use qdrant_client::Qdrant;
client.create_field_index(
CreateFieldIndexCollectionBuilder::new(
"{collection_name}",
"group_id",
FieldType::Keyword,
).field_index_params(
KeywordIndexParamsBuilder::default()
.is_tenant(true)
)
).await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.KeywordIndexParams;
import io.qdrant.client.grpc.Collections.PayloadIndexParams;
import io.qdrant.client.grpc.Collections.PayloadSchemaType;
client
.createPayloadIndexAsync(
"{collection_name}",
"group_id",
PayloadSchemaType.Keyword,
PayloadIndexParams.newBuilder()
.setKeywordIndexParams(
KeywordIndexParams.newBuilder()
.setIsTenant(true)
.build())
.build(),
null,
null,
null)
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
await client.CreatePayloadIndexAsync(
collectionName: "{collection_name}",
fieldName: "group_id",
schemaType: PayloadSchemaType.Keyword,
indexParams: new PayloadIndexParams
{
KeywordIndexParams = new KeywordIndexParams
{
IsTenant = true
}
}
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client.CreateFieldIndex(context.Background(), &qdrant.CreateFieldIndexCollection{
CollectionName: "{collection_name}",
FieldName: "group_id",
FieldType: qdrant.FieldType_FieldTypeKeyword.Enum(),
FieldIndexParams: qdrant.NewPayloadIndexParams(
&qdrant.KeywordIndexParams{
IsTenant: qdrant.PtrOf(true),
}),
})
Include the tenant filter in each query, update, and delete operation that selects points by payload. Derive the tenant identity from the authenticated user, rather than accepting an unrestricted tenant ID from the request.
group_id payload field identifies which tenant owns each point.The tenant index helps storage and search. It does not authorize requests. A client with unrestricted credentials can omit the filter and access other tenants’ points.
Check Whether Shared Resources Fit
A shared collection reduces collection overhead, but its tenants still share resources. Measure latency and indexing behavior for both small and large tenants under the expected concurrent workload.
If indexing is the bottleneck and every search uses a tenant filter, consider the per-tenant HNSW configuration. Setting m: 0 disables the global graph. A positive payload_m retains payload-aware links. Queries without the tenant filter then become slower, so use this configuration only when that trade-off fits the workload.
Sparse retrieval can also share scoring statistics across tenants. Follow per-tenant scoring statistics when each tenant needs its own relevance statistics.
Give Large Tenants Dedicated Shards
Use custom sharding when queries should target a specific group of shards. Create the collection with user-defined sharding, create its shard keys, and send the appropriate shard key with reads and writes. Follow moving shards to control which nodes hold the replicas. Verify their locations with the collection cluster info API. On Qdrant Cloud, disable automatic shard rebalancing before manually controlling shard distribution.
A shard key selects where an operation runs. A payload filter selects which points match within those shards. Use both when a shard contains several tenants.
Dedicated shards consume resources, so creating one for every small tenant can add unnecessary overhead. Prefer payload partitioning for the long tail of small tenants.
Plan for Uneven Tenant Growth
Tiered multitenancy, available from Qdrant 1.16, combines shared and dedicated shards in one collection. Small tenants share a fallback shard. A large tenant can move to a dedicated shard while keeping the same collection.
Configure payload-based tenancy as well as shard routing. The tenant filter remains necessary when a request reaches the shared fallback shard. Follow the documented promotion procedure for moving points and validating the result.
Choose custom sharding when creating the collection if this growth path is required. You cannot change an existing collection’s sharding method in place. Plan capacity carefully: the shared fallback shard must fit on one node.
Use Separate Collections for Different Requirements
Separate collections are useful when a limited number of tenants need different vector schemas, collection settings, or collection-level permissions. They also add resource overhead and increase the number of collections to operate.
Prefer a shared collection when tenants use the same data model and can share its settings. Measure the cost of separate collections before choosing one per tenant.
Enforce Tenant Access
Keep Qdrant behind an authenticated application, or issue appropriately restricted credentials. The application must enforce tenant filters and shard routing for every operation it exposes. Qdrant also supports granular access keys for collection permissions. Keep administrative keys on trusted services.
Validate the chosen design with queries for separate tenants and with attempts to omit or change the tenant identifier. Check that small tenants keep acceptable latency while a large tenant ingests data. Use those results to decide whether shared resources, dedicated shards, or separate collections fit the workload.