Skip to main content
Go to documentation:
⌘U
Weaviate Database

Develop AI applications using Weaviate's APIs and tools

Deploy

Deploy, configure, and maintain Weaviate Database

Query Agent

Run agentic search over your Weaviate Cloud collections

Weaviate Cloud

Manage and scale Weaviate in the cloud

Engram

Persistent memory for LLM agents and applications

Additional resources

Integrations
Weaviate Academy

Need help?

Weaviate LogoAsk AI Assistant⌘K
Support
Community Forum
Contributor guide

Multi-tenancy operations

Multi-tenancy provides data isolation. Each tenant is stored on a separate shard. Data stored in one tenant is not visible to another tenant. If your application serves many different users, multi-tenancy keeps their data private and makes database operations more efficient.

Tenant status renamed in v1.26

In v1.26, the HOT status was renamed to ACTIVE and the COLD status was renamed to INACTIVE.

Enable multi-tenancy​

Multi-tenancy is disabled by default. To enable multi-tenancy, set multiTenancyConfigin the collection definition:

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.config import Configure

multi_collection = client.collections.create(
name="MultiTenancyCollection",
# Enable multi-tenancy on the new collection
multi_tenancy_config=Configure.multi_tenancy(enabled=True)
)
const result = await client.collections.create({
name: collectionName,
multiTenancy: weaviate.configure.multiTenancy({ enabled: true })
})
client.Schema().ClassCreator().
WithClass(&models.Class{
Class: "MultiTenancyCollection",
MultiTenancyConfig: &models.MultiTenancyConfig{
Enabled: true,
},
}).
Do(ctx)
_, err := client.Collections.Create(ctx, collections.Collection{
Name: "MultiTenancyCollection",
MultiTenancy: &collections.MultiTenancyConfig{
Enabled: true,
},
})
if err != nil {
// handle error
panic(err)
}
client.collections.create("MultiTenancyCollection", col -> col
.multiTenancy(mt -> mt.enabled(true).autoTenantCreation(true)));
await client.Collections.Create(
new CollectionCreateParams
{
Name = "MultiTenancyCollection",
MultiTenancyConfig = new MultiTenancyConfig { Enabled = true },
}
);

Automatically add new tenants​

By default, Weaviate returns an error if you try to insert an object into a non-existent tenant. To change this behavior so Weaviate creates a new tenant, set autoTenantCreation to true in the collection definition.

The auto-tenant feature is available from v1.25.0 for batch imports, and from v1.25.2 for single object insertions as well.

Set autoTenantCreation when you create the collection, or reconfigure the collection to update the setting as needed.

Automatic tenant creation is useful when you import a large number of objects. Be cautious if your data is likely to have small inconsistencies or typos. For example, the names TenantOne, tenantOne, and TenntOne will create three different tenants.

Create a collection​

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.config import Configure

multi_collection = client.collections.create(
name="CollectionWithAutoMTEnabled",
# Enable automatic tenant creation
multi_tenancy_config=Configure.multi_tenancy(
enabled=True,
auto_tenant_creation=True
)
)
const result = await client.collections.create({
name: collectionName,
multiTenancy: weaviate.configure.multiTenancy({
enabled: true,
autoTenantCreation: true
})
})
func createClassWithAutoTenantEnabled(ctx context.Context, client *weaviate.Client) {
class := &models.Class{
Class: "AutoTenantEnabledOnCreate",
Properties: []*models.Property{
{Name: "textProp", DataType: []string{"text"}},
},
MultiTenancyConfig: &models.MultiTenancyConfig{
Enabled: true,
AutoTenantCreation: true,
},
}
err := client.Schema().ClassCreator().WithClass(class).Do(ctx)
if err != nil {
log.Fatalf("create class: %v", err)
}
}
_, err := client.Collections.Create(ctx, collections.Collection{
Name: "CollectionWithAutoMTEnabled",
MultiTenancy: &collections.MultiTenancyConfig{
Enabled: true,
AutoTenantCreation: true,
},
})
if err != nil {
// handle error
panic(err)
}
client.collections.create("CollectionWithAutoMTEnabled",
col -> col.multiTenancy(mt -> mt.autoTenantCreation(true)));
await client.Collections.Create(
new CollectionCreateParams
{
Name = "CollectionWithAutoMTEnabled",
MultiTenancyConfig = new MultiTenancyConfig
{
Enabled = true,
AutoTenantCreation = true,
},
}
);
curl localhost:8080/v1/schema -H 'content-type:application/json' -d \
'{
"class": "Customer",
"properties": [
{
"name": "customer_name",
"dataType": ["text"]
},
{
"name": "customer_category",
"dataType": ["text"]
}
],
"multiTenancyConfig": {
"enabled": true,
"autoTenantCreation": true
}
}'

Update a collection​

Use the client to update the auto-tenant creation setting. Auto-tenant is only available for batch inserts.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.config import Reconfigure

collection = client.collections.use(collection_name)

collection.config.update(
multi_tenancy_config=Reconfigure.multi_tenancy(auto_tenant_creation=True)
)
import { reconfigure } from '@weaviate/node';

const multiCollection = client.collections.use(collectionName);

await multiCollection.config.update({
multiTenancy: weaviate.reconfigure.multiTenancy({
autoTenantActivation: true,
autoTenantCreation: true,
}),
});
existing, err := client.Schema().ClassGetter().
WithClassName(class.Class).Do(ctx)
if err != nil {
log.Fatalf("get existing class %q: %v", class.Class, err)
}

existing.MultiTenancyConfig.AutoTenantCreation = true

err = client.Schema().ClassUpdater().WithClass(existing).Do(ctx)
if err != nil {
log.Fatalf("enable autotenant: %v", err)
}
// Coming soon
CollectionHandle<Map<String, Object>> collection =
client.collections.use(collectionName);
collection.config
.update(col -> col.multiTenancy(mt -> mt.autoTenantCreation(true)));
var collection = client.Collections.Use(collectionName);
await collection.Config.Update(c =>
{
c.MultiTenancyConfig.AutoTenantCreation = true;
});

Add new tenants manually​

To add tenants to a collection, specify the collection and the new tenants. Optionally, specify the tenant activity status as ACTIVE(available, default), INACTIVE (not available, on disk), or OFFLOADED (not available, offloaded to cloud).

This example adds tenantA to the MultiTenancyCollection collection:

Additional information

Tenant status is available from Weaviate 1.21 onwards.


Allowable tenant names

A tenant name can only contain alphanumeric characters (a-z, A-Z, 0-9), underscore (_), and hyphen (-), with a length of 4 to 64 characters.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.tenants import Tenant

# Add two tenants to the collection
multi_collection.tenants.create(
tenants=[
Tenant(name="tenantA"),
Tenant(name="tenantB"),
]
)
const multiCollection = client.collections.use(collectionName);

await multiCollection.tenants.create([
{ name: 'tenantA' },
{ name: 'tenantB' }
])
client.Schema().TenantsCreator().
WithClassName("MultiTenancyCollection").
WithTenants(models.Tenant{Name: "tenantA"}, models.Tenant{Name: "tenantB"}).
Do(ctx)
collection := client.Collections.Use("MultiTenancyCollection")

// Add two tenants to the collection
err := collection.Tenants.Create(ctx,
tenant.Tenant{Name: "tenantA"},
tenant.Tenant{Name: "tenantB"},
)
if err != nil {
// handle error
panic(err)
}
collection.tenants.create(Tenant.active("tenantA"),
Tenant.active("tenantB"));
await collection.Tenants.Create(["tenantA", "tenantB"]);

List all tenants​

List existing tenants in a collection.

This example lists the tenants in the MultiTenancyCollection collection:

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

tenants = multi_collection.tenants.get()

print(tenants)
const multiCollection = client.collections.use(collectionName);

let tenants = await multiCollection.tenants.get()

console.log(tenants)
tenants, err := client.Schema().TenantsGetter().
WithClassName("MultiTenancyCollection").
Do(ctx)
collection := client.Collections.Use("MultiTenancyCollection")
// Passing no tenant names returns every tenant in the collection.
tenants, err := collection.Tenants.Get(ctx)
if err != nil {
// handle error
panic(err)
}
for _, tn := range tenants {
fmt.Printf("%s: %s\n", tn.Name, tn.Status)
}
List<Tenant> tenants = collection.tenants.get();
System.out.println(tenants);
var tenants = await collection.Tenants.List();
foreach (var t in tenants)
Console.WriteLine(t.Name);

Get tenants by name​

Get tenants from a collection by name. Note that non-existent tenant names are ignored in the response.

This example returns tenantA and tenantB from the MultiTenancyCollection collection:

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

tenant_names = ["tenantA", "tenantB", "nonExistentTenant"] # `nonExistentTenant`` does not exist and will be ignored
tenants_response = multi_collection.tenants.get_by_names(tenant_names)

for k, v in tenants_response.items():
print(k, v)
const multiCollection = client.collections.use(collectionName);

const tenants = await multiCollection.tenants.getByNames(['tenantA', 'tenantB'])
console.log(tenants)
List<String> tenantNames =
Arrays.asList("tenantA", "tenantB", "nonExistentTenant");
List<Tenant> tenants = collection.tenants.get(tenantNames);
System.out.println(tenants);
var tenantNames = new[] { "tenantA", "tenantB", "nonExistentTenant" };
var tenants = await collection.Tenants.List(tenantNames);
foreach (var t in tenants)
Console.WriteLine(t.Name);

Get one tenant​

Get a particular tenant from a collection.

This example returns a tenant from the MultiTenancyCollection collection:

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

tenant_obj = multi_collection.tenants.get_by_name(tenant_name)

print(tenant_obj.name)
const multiCollection = client.collections.use(collectionName);

const tenant = await multiCollection.tenants.getByName('tenantA')
console.log(tenant)
String tenantName = "tenantA";
Optional<Tenant> tenant = collection.tenants.get(tenantName);
System.out.println(tenant);
string tenantName = "tenantA";
var tenant = await collection.Tenants.Get(tenantName);
Console.WriteLine(tenant?.Name);

Delete tenants​

To delete tenants from a collection, specify the collection (e.g. MultiTenancyCollection) and the tenants (tenantB and tenantX). The delete operation ignores tenant names if a named tenant is not a part of the collection.

Tenant deletion == Tenant data deletion

Deleting a tenant deletes all associated objects.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

# Remove a list of tenants - tenantX will be ignored.
multi_collection.tenants.remove(["tenantB", "tenantX"])
const multiCollection = client.collections.use(collectionName);

await multiCollection.tenants.remove([
{ name: 'tenantB' },
{ name: 'tenantX' } // tenantX will be ignored
])
client.Schema().TenantsDeleter().
WithClassName("MultiTenancyCollection").
WithTenants("tenantB", "tenantX"). // tenantX will be ignored
Do(ctx)
collection := client.Collections.Use("MultiTenancyCollection")
// Unknown tenant names are ignored.
err := collection.Tenants.Delete(ctx, "tenantB", "tenantX")
if err != nil {
// handle error
panic(err)
}
collection.tenants.delete(Arrays.asList("tenantB", "tenantX"));
await collection.Tenants.Delete(new[] { "tenantB", "tenantX" });

Manage tenant states​

Change a tenant state between ACTIVE, INACTIVE, and OFFLOADED.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.tenants import Tenant, TenantActivityStatus

multi_collection = client.collections.use("MultiTenancyCollection")
multi_collection.tenants.update(tenants=[
Tenant(
name="tenantA",
activity_status=TenantActivityStatus.ACTIVE # INACTIVE, OFFLOADED
)
])
const multiCollection = client.collections.use(collectionName)

await multiCollection.tenants.update({
name: 'tenantA',
activityStatus: 'ACTIVE' // 'INACTIVE', 'OFFLOADED'
})
String tenantName = "tenantA";
CollectionHandle<Map<String, Object>> collection =
client.collections.use(collectionName);
collection.tenants.deactivate(tenantName);
collection.tenants.activate(tenantName);
// collection.tenants.offload(tenantName); // Requires S3 offload module
string tenantName = "tenantA";
var multiCollection = client.Collections.Use(collectionName);

// Deactivate
await multiCollection.Tenants.Update([
new Tenant { Name = tenantName, Status = TenantActivityStatus.Inactive },
]);

// Activate
await multiCollection.Tenants.Update([
new Tenant { Name = tenantName, Status = TenantActivityStatus.Active },
]);

// Offloading requires S3/warm/cold configuration
Learn more

See How-to: Manage tenant states for more hands-on examples, and the Guide: Manage resources for more information and strategies to manage hot, warm and cold storage tiers.

CRUD operations​

Multi-tenancy collections require tenant name (e.g. tenantA) with each CRUD operation, as shown in the object creation example below.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

# Get collection specific to the required tenant
multi_tenantA = multi_collection.with_tenant("tenantA")

# Insert an object to tenantA
object_id = multi_tenantA.data.insert(
properties={
"question": "This vector DB is OSS & supports automatic property type inference on import"
}
)
const multiCollection = client.collections.use(collectionName);

const multiTenantA = multiCollection.withTenant('tenantA')

await multiTenantA.data.insert({
question: 'This vector DB is OSS & supports automatic property type inference on import'
})
object, err := client.Data().Creator().
WithClassName("MultiTenancyCollection"). // The class to which the object will be added
WithProperties(map[string]interface{}{
"question": "This vector DB is OSS & supports automatic property type inference on import",
}).
WithTenant("tenantA"). // The tenant to which the object will be added
Do(ctx)
// Bind the tenant to the collection handle.
collection := client.Collections.Use("MultiTenancyCollection",
collections.WithTenant("tenantA"),
)
_, err := collection.Data.Insert(ctx, &data.Object{
Properties: map[string]any{
"question": "This vector DB is OSS & supports automatic property type inference on import",
},
})
if err != nil {
// handle error
panic(err)
}
var jeopardy =
client.collections.use("JeopardyQuestion").withTenant("tenantA");

var uuid = jeopardy.data.insert(Map.of("question",
"This vector DB is OSS & supports automatic property type inference on import"))
.uuid();

System.out.println(uuid); // the return value is the object's UUID
var jeopardy = client.Collections.Use("JeopardyQuestion").WithTenant("tenantA");

var uuid = await jeopardy.Data.Insert(
new
{
question = "This vector DB is OSS & supports automatic property type inference on import",
}
);

Console.WriteLine(uuid); // the return value is the object's UUID

Search queries​

Multi-tenancy collections require the tenant name (e.g. tenantA) with each Get and Aggregate query operation.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
multi_collection = client.collections.use("MultiTenancyCollection")

# Get collection specific to the required tenant
multi_tenantA = multi_collection.with_tenant("tenantA")

# Query tenantA
result = multi_tenantA.query.fetch_objects(
limit=2,
)

print(result.objects[0].properties)
const multiCollection = client.collections.use(collectionName);

const multiTenantA = multiCollection.withTenant('tenantA')

const objectA = await multiTenantA.query.fetchObjects({
limit: 2
})

console.log(objectA.objects)
result, err := client.GraphQL().Get().
WithClassName("MultiTenancyCollection").
WithFields(graphql.Field{Name: "question"}).
WithTenant("tenantA").
Do(ctx)
collection := client.Collections.Use("MultiTenancyCollection",
collections.WithTenant("tenantA"),
)
response, err := collection.Query.OverAll(ctx, query.OverAll{
Limit: 2,
})
if err != nil {
// handle error
panic(err)
}
for _, obj := range response.Objects {
fmt.Printf("%v\n", obj.Properties)
}
var jeopardy =
client.collections.use("JeopardyQuestion").withTenant("tenantA");

var response = jeopardy.query.fetchObjects(c -> c.limit(2));

for (var o : response.objects()) {
System.out.println(o.properties());
}
var jeopardy = client.Collections.Use("JeopardyQuestion").WithTenant("tenantA");

var response = await jeopardy.Query.FetchObjects(limit: 2);

foreach (var o in response.Objects)
{
Console.WriteLine(JsonSerializer.Serialize(o.Properties));
}

Cross-references​

Cross-references and query performance

Queries involving cross-references can be slower than queries that do not involve cross-references, especially at scale such as for multiple objects or complex queries.

At the first instance, we strongly encourage you to consider whether you can avoid using cross-references in your data schema. As a scalable AI database, Weaviate is well-placed to perform complex queries with vector, keyword and hybrid searches involving filters. You may benefit from rethinking your data schema to avoid cross-references where possible.

For example, instead of creating separate "Author" and "Book" collections with cross-references, consider embedding author information directly in Book objects and using searches and filters to find books by author characteristics.

A cross-reference can be added from a multi-tenancy collection object to:

  • A non-multi-tenancy collection object, or
  • An object belonging to the same tenant.

Multi-tenancy collections require the tenant name (e.g. tenantA) when creating, updating or deleting cross-references.

py docs  API docs
More infoCode snippets in the documentation reflect the latest client library and Weaviate Database version. Check the Release notes for specific versions.

If a snippet doesn't work or you have feedback, please open a GitHub issue.
from weaviate.classes.config import ReferenceProperty

multi_collection = client.collections.use("MultiTenancyCollection")
# Add the cross-reference property to the multi-tenancy class
multi_collection.config.add_reference(
ReferenceProperty(
name="hasCategory",
target_collection="JeopardyCategory"
)
)

# Get collection specific to the required tenant
multi_tenantA = multi_collection.with_tenant(tenant="tenantA")

# Add reference from MultiTenancyCollection object to a JeopardyCategory object
multi_tenantA.data.reference_add(
from_uuid=object_id, # MultiTenancyCollection object id (a Jeopardy question)
from_property="hasCategory",
to=category_id # JeopardyCategory id
)
const multiCollection = client.collections.use(collectionName);
// Add the cross-reference property to the multi-tenancy class

await multiCollection.config.addReference({
name: 'hasCategory',
targetCollection: 'JeopardyCategory'
})

const multiTenantA = multiCollection.withTenant('tenantA')

await multiTenantA.data.referenceAdd({
fromUuid: objectId,
fromProperty: 'hasCategory',
to: categoryId
})
// Add the cross-reference property to the multi-tenancy class
client.Schema().PropertyCreator().
WithClassName("MultiTenancyCollection").
WithProperty(&models.Property{
Name: "hasCategory",
DataType: []string{"JeopardyCategory"},
}).
Do(ctx)

// Create the cross-reference from MultiTenancyCollection object to the JeopardyCategory object
client.Data().ReferenceCreator().
WithClassName("MultiTenancyCollection").
WithTenant("tenantA").
WithID(object.ID.String()). // MultiTenancyCollection object id (a Jeopardy question)
WithReferenceProperty("hasCategory").
WithReference(client.Data().ReferencePayloadBuilder().
WithClassName("JeopardyCategory").
WithID(category.ID.String()).
Payload()).
Do(ctx)
collection := client.Collections.Use("MultiTenancyCollection")
// Add the cross-reference property to the multi-tenancy collection
err := collection.Config.AddReference(ctx, collections.Reference{
Name: "hasCategory",
Collections: []string{"JeopardyCategory"},
})
if err != nil {
// handle error
panic(err)
}

// Get a handle bound to the required tenant
tenantA := collection.WithOptions(collections.WithTenant("tenantA"))

// Add a reference from a MultiTenancyCollection object to a JeopardyCategory object
// sourceID: MultiTenancyCollection object id. targetID: JeopardyCategory id.
_, err = tenantA.Data.AddReferences(ctx, data.Reference{
Origin: data.ObjectPath{
Collection: "MultiTenancyCollection",
Property: "hasCategory",
UUID: sourceID,
},
UUID: targetID,
})
if err != nil {
// handle error
panic(err)
}
client.collections.create("JeopardyCategory");
client.collections.create("MultiTenancyCollection",
col -> col.multiTenancy(mt -> mt.enabled(true)));

var categoryCollection = client.collections.use("JeopardyCategory");
var categoryUuid =
categoryCollection.data.insert(Map.of("name", "Test Category"));

var multiCollection = client.collections.use("MultiTenancyCollection");
multiCollection.tenants.create(Tenant.active("tenantA"));

var multiTenantA = multiCollection.withTenant("tenantA");
var referenceObject =
multiTenantA.data.insert(Map.of("title", "Object in Tenant A"));
String objectId = referenceObject.uuid();

multiCollection.config.addReference("hasCategory", "JeopardyCategory");

multiTenantA.data.referenceAdd(objectId, // from_uuid
"hasCategory", // from_property
ObjectReference.object(categoryUuid) // to
);
var multiCollection = client.Collections.Use("MultiTenancyCollection");
await multiCollection.Tenants.Create(["tenantA"]);
// Add the cross-reference property to the multi-tenancy class
await multiCollection.Config.AddReference(
Property.Reference("hasCategory", "JeopardyCategory")
);

// Get collection specific to the required tenant
var multiTenantA = multiCollection.WithTenant("tenantA");

// Insert an object to tenantA
var objectId = await multiTenantA.Data.Insert(
new
{
question = "This vector DB is OSS & supports automatic property type inference on import",
}
);

// Add reference from MultiTenancyCollection object to a JeopardyCategory object
await multiTenantA.Data.ReferenceAdd(
from: objectId, // MultiTenancyCollection object id (a Jeopardy question)
fromProperty: "hasCategory",
to: categoryId // JeopardyCategory id
);

Backups​

Backups do not include offloaded tenants

Backups of multi-tenant collections include both active and inactive tenants. Inactive tenants are read directly from disk, so you do not need to activate them before creating a backup.

Offloaded tenants are not included, because their data is not held on local disk. The tenant status is preserved, but the tenant's data is not part of the backup. Activate offloaded tenants before creating a backup to include their data.

Support for backing up inactive tenants was added in v1.37.0, and backported to v1.35.17 and v1.36.10. In earlier releases, backups include only active tenants.

Questions and feedback​