🎉 Seed RoundWe've raised 2.5M from Swift, YC, & Chapter One. Read more

Tutorial - 2023-06-29

How to build Multi-Tenant Applications in Metal

by Pablo Rios

Metal heads sitting in a multi-tenant living room

Metal heads sitting in a multi-tenant living room

Metal empowers fast, accurate, and scalable embedding retrieval for your applications, making it ideal for various tasks like semantic search, question-answering, and recommendation systems.

One standout feature of Metal is its support for metadata filters, which allows you to serve different data to different users based on their preferences, needs, or access rights. This is especially useful for building multi-tenant applications, where you have multiple users or tenants who share the same infrastructure but have different data needs.

For example, a company may want to provide a semantic search for its internal documents but only allow authorized employees to access certain documents. Another company may want to offer personalized recommendations for its customers but only show products that are relevant and available for each customer. So the question is: how do we ensure that each user only sees the relevant results for their data?

To tackle this, we will cover two strategies for building multi-tenant applications in Metal:

  1. Metadata filters: This involves storing all your embeddings in a single index and applying metadata filters at query time to filter out the relevant embeddings for each tenant.
  2. Separate index: This involves creating a separate index for each tenant and storing their embeddings individually.

Metadata Filters

The first strategy is to use a single index for all your tenants and use metadata filters to differentiate them. Metadata is additional information that you can attach to each embedding, such as the tenant ID, category, price, availability, etc. Metadata filters can be used to implement access control policies, personalization strategies, or any other logic that depends on the metadata attributes.

The advantages of this strategy are:

  • It simplifies index management and reduces the storage cost. You only need to maintain one index for all your tenants.
  • It enables cross-tenant queries and analytics. You can query across multiple tenants by using metadata filters or aggregations.

The disadvantages of this strategy are:

  • It is not possible to customize tenant specifications at the index level when provisioning, thereby restricting the ability to provide unique configurations for each tenant.

Separate index

The second strategy involves using a separate index for each tenant, following a 'silo' model that offers dedicated resources to each tenant. To implement this strategy, you will create an individual index for each tenant in Metal and push their embeddings separately. This approach allows you to add metadata attributes to each separate index, providing further customization and flexibility. When querying you will need to specify the index name, ensuring that each tenant can only access the embeddings stored within their respective index.

The advantages of this strategy are:

  • It enhances the security and privacy of your data. Each index will be isolated from other indexes and tenants.
  • It improves the performance and scalability of your application. Each index will have a smaller size and simpler queries.

The disadvantages of this strategy are:

  • It complicates index management and increases the storage cost. You need to create and maintain multiple indexes for each tenant.
  • It prevents cross-tenant queries and analytics. You cannot query across multiple indexes or tenants.

Real-World Use Case: Semantic Search for Internal Documents

To illustrate how to use metadata filters, let's consider a concrete example of an organization that wants to use Metal to provide a semantic search for its internal documents.

The organization has a large collection of documents, such as reports, presentations, emails, etc., that are stored in a cloud storage service. The organization wants to use Metal to index documents and enable its employees to search for them using natural language queries.

However, it also has some requirements and constraints:

  • The organization has multiple departments, such as sales, marketing, engineering, etc., and each department has its own set of documents. The organization wants to restrict access to the documents based on the department of the employee. For example, only sales employees can access sales documents, and only engineering employees can access engineering documents.
  • The organization wants to optimize the performance and cost of its application. It does not want to create and maintain a separate index for each department, as it would increase the storage cost and complicate index management.

To meet these requirements and constraints, the organization can use the metadata filtering strategy to implement its multi-tenant application in Metal. Here are the steps that the organization needs to follow:

Step 1: Define the Metadata Schema

In the Metal Dashboard, create an Index and include the metadata attributes. These attributes can be used to identify the organization_id and the department name such as "sales" or "engineering". The platform allows up to 3 attributes in the schema and supports Number and String data types by default.

Index creation

Index creation

Step 2: Add Metadata to Documents

Incorporate the relevant metadata into your Documents and push them to your Index. Ensure that the metadata key-value pairs align with the ones created in the previous step. By doing so, you can provide tailored instructions for onboarding employees based on their specific departments.

'text': 'Onboarding and orientation program',
'metadata': {
'department': 'sales'
(async () => {
const embeddingDocument = await metal.index({
text: 'Onboarding and orientation program',
metadata: {
organization_id: 123,
department: 'sales',

Step 3: Query your Documents

To query your documents, you can make use of the search API endpoint and apply metadata filters using the filter parameter. For instance, you have the option to filter based on "organization_id": 123 or "department": "engineering". Additionally, you can utilize the limit parameter to specify the desired number of results.

results = metal.search({
'text': 'What are the key metrics to track?',
'filters': [{
'value': 'engineering',
}, limit=3)
(async () => {
const results = await metal.search({
text: 'What are the key metrics to track?',
filters: [{ field: 'department', value: 'engineering' }],
limit: 3,

The response will contain a list of the top 3 documents that match the query text and the metadata filters, sorted by relevance score.


By adopting this approach, an organization can build a multi-tenancy application in Metal that uses metadata filters to serve different data to different users based on specific criteria. This not only enables fine-grained access control but also optimizes performance and reduces costs for semantic search applications.

We hope this post has given you some insights and ideas on how to use Metal for your own multi-tenant applications. If you want to learn more about Metal and how it works, you can check out the Metal documentation.

Happy coding! 🤟