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.
Multi-tenancy availability
- Multi-tenancy added in
v1.20
- Tenant activity status setting added in
v1.21
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 multiTenancyConfig
in the collection definition:
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
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)
)
client.schema.create_class({
"class": "MultiTenancyCollection",
"multiTenancyConfig": {"enabled": True}
})
const result = await client.collections.create({
name: 'MultiTenancyCollection',
multiTenancy: weaviate.configure.multiTenancy({enabled: true, autoTenantCreation: true})
})
await client.schema
.classCreator().withClass({
class: 'MultiTenancyCollection',
multiTenancyConfig: { enabled: true },
})
.do();
WeaviateClass multiTenancyCollection = WeaviateClass.builder()
.className("MultiTenancyCollection")
.multiTenancyConfig(MultiTenancyConfig.builder().enabled(true).build())
.build();
client.schema().classCreator()
.withClass(multiTenancyCollection)
.run();
client.Schema().ClassCreator().
WithClass(&models.Class{
Class: "MultiTenancyCollection",
MultiTenancyConfig: &models.MultiTenancyConfig{
Enabled: true,
},
}).
Do(ctx)
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
- Python Client v4
- JS/TS Client v3
- Go
- cURL
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: 'MultiTenancyCollection',
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)
}
}
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.
- Python Client v4
- JS/TS Client v3
- Go
from weaviate.classes.config import Reconfigure
collection = client.collections.get(collection_name)
collection.config.update(
multi_tenancy_config=Reconfigure.multi_tenancy(auto_tenant_creation=True)
)
import { reconfigure } from 'weaviate-client';
const multiCollection = client.collections.get('MultiTenancyCollection');
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)
}
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.
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.
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
from weaviate.classes.tenants import Tenant
# Add two tenants to the collection
multi_collection.tenants.create(
tenants=[
Tenant(name="tenantA"),
Tenant(name="tenantB"),
]
)
from weaviate import Tenant
client.schema.add_class_tenants(
class_name="MultiTenancyCollection", # The class to which the tenants will be added
tenants=[Tenant(name="tenantA"), Tenant(name="tenantB")]
)
const multiCollection = client.collections.get('MultiTenancyCollection');
await multiCollection.tenants.create([
{ name: 'tenantA'},
{ name: 'tenantB'}
])
let tenants = await client.schema
.tenantsCreator(
'MultiTenancyCollection',
[{ name: 'tenantA' }, { name: 'tenantB' }]
)
.do();
client.schema().tenantsCreator()
.withClassName("MultiTenancyCollection")
.withTenants(
Tenant.builder().name("tenantA").build(),
Tenant.builder().name("tenantB").build()
)
.run();
client.Schema().TenantsCreator().
WithClassName("MultiTenancyCollection").
WithTenants(models.Tenant{Name: "tenantA"}, models.Tenant{Name: "tenantB"}).
Do(ctx)
List all tenants
List existing tenants in a collection.
This example lists the tenants in the MultiTenancyCollection
collection:
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
multi_collection = client.collections.get("MultiTenancyCollection")
tenants = multi_collection.tenants.get()
print(tenants)
tenants = client.schema.get_class_tenants(
class_name="MultiTenancyCollection" # The class from which the tenants will be retrieved
)
const multiCollection = client.collections.get('MultiTenancyCollection');
let tenants = await multiCollection.tenants.get()
console.log(tenants)
tenants = await client.schema
.tenantsGetter('MultiTenancyCollection')
.do();
client.schema().tenantsGetter()
.withClassName("MultiTenancyCollection")
.run();
tenants, err := client.Schema().TenantsGetter().
WithClassName("MultiTenancyCollection").
Do(ctx)
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:
- Python Client v4
- JS/TS Client v3
multi_collection = client.collections.get("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.get('MultiTenancyCollection');
const tenants = await multiCollection.tenants.getByNames(['tenantA', 'tenantB'])
console.log(tenants)
Get one tenant
Get a particular tenant from a collection.
This example returns a tenant from the MultiTenancyCollection
collection:
- Python Client v4
- JS/TS Client v3
multi_collection = client.collections.get("MultiTenancyCollection")
tenant_obj = multi_collection.tenants.get_by_name(tenant_name)
print(tenant_obj.name)
const multiCollection = client.collections.get('MultiTenancyCollection');
const tenant = await multiCollection.tenants.getByName('tenantA')
console.log(tenant)
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.
Deleting a tenant deletes all associated objects.
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
multi_collection = client.collections.get("MultiTenancyCollection")
# Remove a list of tenants - tenantX will be ignored.
multi_collection.tenants.remove(["tenantB", "tenantX"])
client.schema.remove_class_tenants(
class_name="MultiTenancyCollection", # The class from which the tenants will be removed
tenants=["tenantB", "tenantX"] # The tenants to be removed. tenantX will be ignored.
)
const multiCollection = client.collections.get('MultiTenancyCollection');
await multiCollection.tenants.remove([
{ name: 'tenantB' },
{ name: 'tenantX' } // tenantX will be ignored
])
await client.schema
.tenantsDeleter('MultiTenancyCollection', ['tenantB', 'tenantX']) // tenantX will be ignored
.do();
client.schema().tenantsDeleter()
.withClassName("MultiTenancyCollection")
.withTenants("tenantB", "tenantX") // tenantX will be ignored
.run();
client.Schema().TenantsDeleter().
WithClassName("MultiTenancyCollection").
WithTenants("tenantB", "tenantX"). // tenantX will be ignored
Do(ctx)
Manage tenant states
Change a tenant state between ACTIVE
, INACTIVE
, and OFFLOADED
.
- Python Client v4
- JS/TS Client v3
from weaviate.classes.tenants import Tenant, TenantActivityStatus
multi_collection = client.collections.get("MultiTenancyCollection")
multi_collection.tenants.update(tenants=[
Tenant(
name="tenantA",
activity_status=TenantActivityStatus.ACTIVE # INACTIVE, OFFLOADED
)
])
const multiCollection = client.collections.get('MultiTenancyCollection')
await multiCollection.tenants.update({
name: 'tenantA',
activityStatus: 'ACTIVE' // 'INACTIVE', 'OFFLOADED'
})
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.
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
multi_collection = client.collections.get("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"
}
)
object_id = client.data_object.create(
class_name="MultiTenancyCollection", # The class to which the object will be added
data_object={
"question": "This vector DB is OSS & supports automatic property type inference on import"
},
tenant="tenantA" # The tenant to which the object will be added
)
const multiCollection = client.collections.get('MultiTenancyCollection');
const multiTenantA = multiCollection.withTenant('tenantA')
await multiTenantA.data.insert({
question: 'This vector DB is OSS & supports automatic property type inference on import'
})
let object = await client.data.creator()
.withClassName('MultiTenancyCollection') // The class to which the object will be added
.withProperties({
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();
Result<WeaviateObject> result = client.data().creator()
.withClassName("MultiTenancyCollection") // The class to which the object will be added
.withProperties(new HashMap<String, Object>() {{
put("question", "This vector DB is OSS & supports automatic property type inference on import");
}})
.withTenant("tenantA") // The tenant to which the object will be added
.run();
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)
Search queries
Multi-tenancy collections require the tenant name (e.g. tenantA
) with each Get
and Aggregate
query operation.
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
multi_collection = client.collections.get("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)
result = (
client.query.get("MultiTenancyCollection", ["question"])
.with_tenant("tenantA")
.do()
)
const multiCollection = client.collections.get('MultiTenancyCollection');
const multiTenantA = multiCollection.withTenant('tenantA')
const objectA = await multiTenantA.query.fetchObjects({
limit: 2
})
console.log(objectA.objects)
const result = await client.graphql
.get()
.withClassName('MultiTenancyCollection')
.withFields('question')
.withTenant('tenantA')
.do();
Result<GraphQLResponse> result = client.graphQL().get()
.withClassName("MultiTenancyCollection")
.withFields(Field.builder().name("question").build())
.withTenant("tenantA")
.run();
result, err := client.GraphQL().Get().
WithClassName("MultiTenancyCollection").
WithFields(graphql.Field{Name: "question"}).
WithTenant("tenantA").
Do(ctx)
Cross-references
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.
- Python Client v4
- Python Client v3
- JS/TS Client v3
- JS/TS Client v2
- Java
- Go
from weaviate.classes.config import ReferenceProperty
multi_collection = client.collections.get("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
)
# Add the cross-reference property to the multi-tenancy class
client.schema.property.create("MultiTenancyCollection", {
"name": "hasCategory",
"dataType": ["JeopardyCategory"],
})
client.data_object.reference.add(
from_uuid=object_id, # MultiTenancyCollection object id (a Jeopardy question)
from_class_name="MultiTenancyCollection",
from_property_name="hasCategory",
tenant="tenantA",
to_class_name="JeopardyCategory",
to_uuid=category_id
)
const multiCollection = client.collections.get('MultiTenancyCollection');
// 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
await client.schema.propertyCreator()
.withClassName('MultiTenancyCollection')
.withProperty({
'name': 'hasCategory',
'dataType': ['JeopardyCategory'],
})
.do();
// Create the cross-reference from MultiTenancyCollection object to the JeopardyCategory object
await client.data
.referenceCreator()
.withClassName('MultiTenancyCollection')
.withTenant('tenantA')
.withId(object.id) // MultiTenancyCollection object id (a Jeopardy question)
.withReferenceProperty('hasCategory')
.withReference(
client.data
.referencePayloadBuilder()
.withClassName('JeopardyCategory')
.withId(category.id)
.payload()
)
.do();
// Add the cross-reference property to the multi-tenancy class
client.schema().propertyCreator()
.withClassName("MultiTenancyCollection")
.withProperty(Property.builder()
.name("hasCategory")
.dataType(Collections.singletonList("JeopardyCategory")).build()
)
.run();
// Create the cross-reference from MultiTenancyCollection object to the JeopardyCategory object
client.data().referenceCreator()
.withClassName("MultiTenancyCollection")
.withTenant("tenantA")
.withID(object.getId()) // MultiTenancyCollection object id (a Jeopardy question)
.withReferenceProperty("hasCategory")
.withReference(
client.data()
.referencePayloadBuilder()
.withClassName("JeopardyCategory")
.withID(category.getId())
.payload()
)
.run();
// 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)
Backups
Backups of multi-tenant collections will only include active
tenants, and not inactive
or offloaded
tenants. Activate tenants before creating a backup to ensure all data is included.
Related pages
- Connect to Weaviate
- How to: Configure a schema
- References: REST API: Schema
- Concepts: Data Structure: Multi-tenancy
Questions and feedback
If you have any questions or feedback, let us know in the user forum.