---
title: "Migrate data"
description: "Learn how to migrate data within Weaviate for easy data handling."
url: https://docs.weaviate.io/weaviate/manage-collections/migrate
---

# Migrate data

Follow these examples to migrate data manually when using a backup is not possible. They cover all permutations between:

- a single-tenancy collection (Collection), and
- a tenant in a multi-tenancy collection (Tenant).

**Additional information**

The examples use two different Weaviate instances, exposed through different ports. The same process can be used for two different instances as well.

Cross-references in Weaviate are properties. As such, you can [retrieve cross-reference](https://docs.weaviate.io/weaviate/manage-collections/cross-references#read-cross-references) as a part of the object.

**What about cross-references?**

These scripts should migrate cross-references as well.



Cross-references are properties. As such, these cursor-based exports will include them. During restoration, restore the cross-referenced (i.e. "to") object first, then the object that contains the cross-reference (i.e. "from" object).

## Collection → Collection

#### Step 1: Create the target collection(s)

Create a collection (e.g. `WineReview`) at the target instance, matching the collection (e.g. `WineReview`) at the source instance.

**Python**

```py
import weaviate
import weaviate.classes as wvc
from weaviate.collections import Collection
from weaviate.client import WeaviateClient

client_src = weaviate.connect_to_local(
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

client_tgt = weaviate.connect_to_local(
    port=8090,
    grpc_port=50061,
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

def create_collection(client_in: WeaviateClient, collection_name: str, enable_mt=False):

    reviews = client_in.collections.create(
        name=collection_name,
        multi_tenancy_config=wvc.config.Configure.multi_tenancy(enabled=enable_mt),
        # Additional settings not shown
    )

    return reviews


reviews_tgt = create_collection(client_tgt, "WineReview", enable_mt=False)
```

**JavaScript/TypeScript**

```ts
import weaviate, { Collection, WeaviateClient } from '@weaviate/node'

let client_src: WeaviateClient,client_tgt: WeaviateClient;
let reviews_mt_tgt, reviews_mt_src;
let reviews_tgt, reviews_src;

client_src = await weaviate.connectToLocal({
})

client_tgt = await weaviate.connectToLocal({
    port: 8090,
    grpcPort: 50061,
})

async function createCollection(clientIn: WeaviateClient, collectionName: string, enableMt: boolean) {
    let reviews = clientIn.collections.create({
        name: collectionName,
        multiTenancy: {
            enabled: enableMt
        },
        // Additional settings not shown
    })

    return reviews
}

reviews_tgt = await createCollection(client_tgt, "WineReview", false)
```

**Java**

```java
  private static CollectionHandle<Map<String, Object>> createCollection(
      WeaviateClient clientIn, String collectionName, boolean enableMt)
      throws IOException {
    clientIn.collections.create(collectionName,
        col -> col.multiTenancy(c -> c.enabled(enableMt))
            // Additional settings not shown
            .vectorConfig(VectorConfig.text2vecTransformers())
            .generativeModule(Generative.cohere())
            .properties(Property.text("review_body"), Property.text("title"),
                Property.text("country"), Property.integer("points"),
                Property.number("price")));

    return clientIn.collections.use(collectionName);
  }

  void createCollectionToCollection() throws IOException {
    createCollection(clientTgt, "WineReview", false);
  }
```

**C#**

```csharp
private static async Task<CollectionClient> CreateCollection(
    WeaviateClient clientIn,
    string collectionName,
    bool enableMt
)
{
    return await clientIn.Collections.Create(
        new CollectionCreateParams
        {
            Name = collectionName,
            MultiTenancyConfig = new MultiTenancyConfig { Enabled = enableMt },
            VectorConfig = Configure.Vector("default", v => v.Text2VecTransformers()),
            Properties =
            [
                Property.Text("review_body"),
                Property.Text("title"),
                Property.Text("country"),
                Property.Int("points"),
                Property.Number("price"),
            ],
        }
    );
}

private async Task CreateCollectionToCollection()
{
    await CreateCollection(clientTgt, "WineReview", false);
}
```

#### Step 2: Migrate the data

Migrate:

- The `source collection` data in the `client_src` instance
- to `target collection` in the `client_tgt` instance

**Python**

```py
def migrate_data(collection_src: Collection, collection_tgt: Collection):

    with collection_tgt.batch.fixed_size(batch_size=100) as batch:
        for q in tqdm(collection_src.iterator(include_vector=True)):
            batch.add_object(
                properties=q.properties,
                vector={
                    "default": q.vector["default"],
                },
                uuid=q.uuid
            )

    return True


reviews_src = client_src.collections.get("WineReview")
reviews_tgt = client_tgt.collections.get("WineReview")

migrate_data(reviews_src, reviews_tgt)

client_src.close()
client_tgt.close()
```

**JavaScript/TypeScript**

```ts
let reviews_tgt, reviews_src;
reviews_src = client_src.collections.use("WineReview")
reviews_tgt = client_tgt.collections.use("WineReview")

let maxItems = await reviews_src.length()
let counter: number = 0

async function migrateData(collection_src: Collection, collection_tgt: Collection) {
    let itemsToInsert = []
    const promises = []

    for await (const item of collection_src.iterator({ includeVector: true })) {
        // Check if we've reached the maximum items
        if (counter >= maxItems) {
            console.log(`Reached maximum items limit of ${maxItems}`);
            break;
        }

        counter++;
        if (counter % 500 == 0)
            console.log(`Import: ${counter}`)

        let objectToInsert = {
            properties: item.properties,
            vectors: item.vectors.default,
            uuid: item.uuid,
        }

        // Add object to batching array
        itemsToInsert.push(objectToInsert)

        if (itemsToInsert.length == 500 || counter == maxItems) {
            try {
                const response = await collection_tgt.data.insertMany(itemsToInsert);

                if (response.hasErrors) {
                    throw new Error("Error in batch import!");
                }

                console.log(`Successfully imported batch of ${itemsToInsert.length} items`);
                itemsToInsert = [];
            } catch (error) {
                console.error('Error importing batch:', error);
            }
        }
    }
   
}

migrateData(reviews_src, reviews_tgt)

client_src.close()
client_tgt.close()
```

**Java**

```java
  private void migrateData(CollectionHandle<Map<String, Object>> collectionSrc,
      CollectionHandle<Map<String, Object>> collectionTgt) {
    System.out.println("Starting data migration...");
    List<WeaviateObject<Map<String, Object>>> sourceObjects = StreamSupport
        .stream(collectionSrc.paginate(p -> p.includeVector()).spliterator(),
            false)
        .map(readObj -> WeaviateObject
            .<Map<String, Object>>of(c -> c.properties(readObj.properties())
                .uuid(readObj.uuid())
                .vectors(readObj.vectors())))
        .collect(Collectors.toList());

    collectionTgt.data.insertMany(sourceObjects);

    System.out.println("Data migration complete.");
  }

  void testCollectionToCollection() throws IOException {
    createCollectionToCollection();

    var reviewsSrc = clientSrc.collections.use("WineReview");
    var reviewsTgt = clientTgt.collections.use("WineReview");
    migrateData(reviewsSrc, reviewsTgt);

  }
```

**C#**

```csharp
private async Task MigrateData<T>(
    CollectionClient collectionSrc,
    CollectionClient collectionTgt
)
{
    Console.WriteLine("Starting data migration...");

    // Fetch source objects
    var response = await collectionSrc.Query.FetchObjects(limit: 10000, includeVectors: true);

    // Map to Strong Type List
    var sourceObjects = new List<T>();
    foreach (var obj in response.Objects)
    {
        // Deserialize the inner properties Dictionary to the POCO type
        var json = JsonSerializer.Serialize(obj.Properties);
        var typedObj = JsonSerializer.Deserialize<T>(json);
        if (typedObj != null)
        {
            sourceObjects.Add(typedObj);
        }
    }

    // InsertMany using Strong Types
    await collectionTgt.Data.InsertMany(sourceObjects.ToArray());

    Console.WriteLine($"Data migration complete. Migrated {sourceObjects.Count} objects.");
}

public async Task TestCollectionToCollection()
{
    await CreateCollectionToCollection();

    var reviewsSrc = clientSrc.Collections.Use("WineReview");
    var reviewsTgt = clientTgt.Collections.Use("WineReview");

    // Pass the Type to the generic method
}
```

## Collection → Tenant

#### Step 1: Create the target collection(s)

Create a collection (e.g. `WineReview`) at the target instance, matching the collection (e.g. `WineReview`) at the source instance, and enable multi-tenancy for the target collection.

**Python**

```py
import weaviate
import weaviate.classes as wvc
from weaviate.collections import Collection
from weaviate.client import WeaviateClient

client_src = weaviate.connect_to_local(
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

client_tgt = weaviate.connect_to_local(
    port=8090,
    grpc_port=50061,
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

def create_collection(client_in: WeaviateClient, collection_name: str, enable_mt=False):

    reviews = client_in.collections.create(
        name=collection_name,
        multi_tenancy_config=wvc.config.Configure.multi_tenancy(enabled=enable_mt),
        # Additional settings not shown
    )

    return reviews


reviews_mt_tgt = create_collection(client_tgt, "WineReviewMT", enable_mt=True)
```

**JavaScript/TypeScript**

```ts
import weaviate, { Collection, WeaviateClient } from '@weaviate/node'

let client_src: WeaviateClient,client_tgt: WeaviateClient;
let reviews_mt_tgt, reviews_mt_src;

client_src = await weaviate.connectToLocal({
})

client_tgt = await weaviate.connectToLocal({
    port: 8090,
    grpcPort: 50061,
})

async function createCollection(clientIn: WeaviateClient, collectionName: string, enableMt: boolean) {
    let reviews = clientIn.collections.create({
        name: collectionName,
        multiTenancy: {
            enabled: enableMt
        },
        // Additional settings not shown
    })

    return reviews
}

reviews_mt_tgt = createCollection(client_tgt, "WineReviewMT", true)
```

**Java**

```java
  private static CollectionHandle<Map<String, Object>> createCollection(
      WeaviateClient clientIn, String collectionName, boolean enableMt)
      throws IOException {
    clientIn.collections.create(collectionName,
        col -> col.multiTenancy(c -> c.enabled(enableMt))
            // Additional settings not shown
            .vectorConfig(VectorConfig.text2vecTransformers())
            .generativeModule(Generative.cohere())
            .properties(Property.text("review_body"), Property.text("title"),
                Property.text("country"), Property.integer("points"),
                Property.number("price")));

    return clientIn.collections.use(collectionName);
  }

  void createCollectionToTenant() throws IOException {
    createCollection(clientTgt, "WineReviewMT", true);
  }
```

**C#**

```csharp
private static async Task<CollectionClient> CreateCollection(
    WeaviateClient clientIn,
    string collectionName,
    bool enableMt
)
{
    return await clientIn.Collections.Create(
        new CollectionCreateParams
        {
            Name = collectionName,
            MultiTenancyConfig = new MultiTenancyConfig { Enabled = enableMt },
            VectorConfig = Configure.Vector("default", v => v.Text2VecTransformers()),
            Properties =
            [
                Property.Text("review_body"),
                Property.Text("title"),
                Property.Text("country"),
                Property.Int("points"),
                Property.Number("price"),
            ],
        }
    );
}

private async Task CreateCollectionToTenant()
{
    await CreateCollection(clientTgt, "WineReviewMT", true);
}
```

#### Step 2: Create the tenant(s)

Add tenants at the target instance before adding data objects.

**Python**

```py
tenants_tgt = [wvc.tenants.Tenant(name="tenantA"), wvc.tenants.Tenant(name="tenantB")]

reviews_mt_tgt = client_tgt.collections.get("WineReviewMT")
reviews_mt_tgt.tenants.create(tenants_tgt)
```

**JavaScript/TypeScript**

```ts
let tenantsTgt = [
    { name: 'tenantA'},
    { name: 'tenantB'}
  ]

reviews_mt_tgt = client_tgt.collections.use("WineReviewMT")
reviews_mt_tgt.tenants.create(tenantsTgt)
```

**Java**

```java
  void createTenants() throws IOException {
    var reviewsMtTgt = clientTgt.collections.use("WineReviewMT");

    var tenantsTgt =
        List.of(Tenant.active("tenantA"), Tenant.active("tenantB"));
    reviewsMtTgt.tenants.create(tenantsTgt);
  }
```

**C#**

```csharp
private async Task CreateTenants()
{
    var reviewsMtTgt = clientTgt.Collections.Use("WineReviewMT");

    var tenantsTgt = new[]
    {
        new Tenant { Name = "tenantA" },
        new Tenant { Name = "tenantB" },
    };
    await reviewsMtTgt.Tenants.Create(tenantsTgt);
}
```

#### Step 3: Migrate the data

Migrate:

- The `source collection` data in the `client_src` instance
- to `target tenant` data from `target collection` in the `client_tgt` instance

**Python**

```py
def migrate_data(collection_src: Collection, collection_tgt: Collection):

    with collection_tgt.batch.fixed_size(batch_size=100) as batch:
        for q in tqdm(collection_src.iterator(include_vector=True)):
            batch.add_object(
                properties=q.properties,
                vector={
                    "default": q.vector["default"],
                },
                uuid=q.uuid
            )

    return True


reviews_src = client_src.collections.get("WineReview")
reviews_mt_tgt = client_tgt.collections.get("WineReviewMT")
reviews_tgt_tenant_a = reviews_mt_tgt.with_tenant(tenants_tgt[0].name)

migrate_data(reviews_src, reviews_tgt_tenant_a)

client_src.close()
client_tgt.close()
```

**JavaScript/TypeScript**

```ts
let reviews_tgt, reviews_src;

reviews_src = client_src.collections.use("WineReview")
reviews_mt_tgt = client_tgt.collections.use("WineReviewMT")

let maxItems = await reviews_src.length()
let counter: number = 0

async function migrateData(collection_src: Collection, collection_tgt: Collection) {
    let itemsToInsert = []
    const promises = []

    for await (const item of collection_src.iterator({ includeVector: true })) {
        // Check if we've reached the maximum items
        if (counter >= maxItems) {
            console.log(`Reached maximum items limit of ${maxItems}`);
            break;
        }

        counter++;
        if (counter % 500 == 0)
            console.log(`Import: ${counter}`)

        let objectToInsert = {
            properties: item.properties,
            vectors: item.vectors.default,
            uuid: item.uuid,
        }

        // Add object to batching array
        itemsToInsert.push(objectToInsert)

        if (itemsToInsert.length == 500 || counter == maxItems) {
            try {
                const response = await collection_tgt.data.insertMany(itemsToInsert);

                if (response.hasErrors) {
                    throw new Error("Error in batch import!");
                }

                console.log(`Successfully imported batch of ${itemsToInsert.length} items`);
                itemsToInsert = [];
            } catch (error) {
                console.error('Error importing batch:', error);
            }
        }
    }
   
}

let reviews_tgt_tenant_a = reviews_mt_tgt.withTenant(tenantsTgt[0].name)
migrateData(reviews_src, reviews_tgt_tenant_a)

client_src.close()
client_tgt.close()
```

**Java**

```java
  private void migrateData(CollectionHandle<Map<String, Object>> collectionSrc,
      CollectionHandle<Map<String, Object>> collectionTgt) {
    System.out.println("Starting data migration...");
    List<WeaviateObject<Map<String, Object>>> sourceObjects = StreamSupport
        .stream(collectionSrc.paginate(p -> p.includeVector()).spliterator(),
            false)
        .map(readObj -> WeaviateObject
            .<Map<String, Object>>of(c -> c.properties(readObj.properties())
                .uuid(readObj.uuid())
                .vectors(readObj.vectors())))
        .collect(Collectors.toList());

    collectionTgt.data.insertMany(sourceObjects);

    System.out.println("Data migration complete.");
  }

  void testCollectionToTenant() throws IOException {
    createCollectionToTenant();
    createTenants();

    var reviewsMtTgt = clientTgt.collections.use("WineReviewMT");
    var reviewsSrc = clientSrc.collections.use("WineReview");

    var reviewsTgtTenantA = reviewsMtTgt.withTenant("tenantA");

    migrateData(reviewsSrc, reviewsTgtTenantA);
  }
```

**C#**

```csharp
private async Task MigrateData<T>(
    CollectionClient collectionSrc,
    CollectionClient collectionTgt
)
{
    Console.WriteLine("Starting data migration...");

    // Fetch source objects
    var response = await collectionSrc.Query.FetchObjects(limit: 10000, includeVectors: true);

    // Map to Strong Type List
    var sourceObjects = new List<T>();
    foreach (var obj in response.Objects)
    {
        // Deserialize the inner properties Dictionary to the POCO type
        var json = JsonSerializer.Serialize(obj.Properties);
        var typedObj = JsonSerializer.Deserialize<T>(json);
        if (typedObj != null)
        {
            sourceObjects.Add(typedObj);
        }
    }

    // InsertMany using Strong Types
    await collectionTgt.Data.InsertMany(sourceObjects.ToArray());

    Console.WriteLine($"Data migration complete. Migrated {sourceObjects.Count} objects.");
}

public async Task TestCollectionToTenant()
{
    await CreateCollectionToTenant();
    await CreateTenants();

    var reviewsMtTgt = clientTgt.Collections.Use("WineReviewMT");
    var reviewsSrc = clientSrc.Collections.Use("WineReview");

    var reviewsTgtTenantA = reviewsMtTgt.WithTenant("tenantA");

    await MigrateData<WineReviewModel>(reviewsSrc, reviewsTgtTenantA);
}
```

## Tenant → Collection

#### Step 1: Create the target collection(s)

Create a collection (e.g. `WineReview`) at the target instance, matching the collection (e.g. `WineReview`) at the source instance, and enable multi-tenancy for the target collection.

**Python**

```py
import weaviate
import weaviate.classes as wvc
from weaviate.collections import Collection
from weaviate.client import WeaviateClient

client_src = weaviate.connect_to_local(
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

client_tgt = weaviate.connect_to_local(
    port=8090,
    grpc_port=50061,
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

def create_collection(client_in: WeaviateClient, collection_name: str, enable_mt=False):

    reviews = client_in.collections.create(
        name=collection_name,
        multi_tenancy_config=wvc.config.Configure.multi_tenancy(enabled=enable_mt),
        # Additional settings not shown
    )

    return reviews


reviews_tgt = create_collection(client_tgt, "WineReview", enable_mt=False)
```

**JavaScript/TypeScript**

```ts
import weaviate, { Collection, WeaviateClient } from '@weaviate/node'

let client_src: WeaviateClient,client_tgt: WeaviateClient;
let reviews_mt_tgt, reviews_mt_src;

client_src = await weaviate.connectToLocal({
})

client_tgt = await weaviate.connectToLocal({
    port: 8090,
    grpcPort: 50061,
})

async function createCollection(clientIn: WeaviateClient, collectionName: string, enableMt: boolean) {
    let reviews = clientIn.collections.create({
        name: collectionName,
        multiTenancy: {
            enabled: enableMt
        },
        // Additional settings not shown
    })

    return reviews
}

reviews_tgt = await createCollection(client_tgt, "WineReview", false)
```

**Java**

```java
  private static CollectionHandle<Map<String, Object>> createCollection(
      WeaviateClient clientIn, String collectionName, boolean enableMt)
      throws IOException {
    clientIn.collections.create(collectionName,
        col -> col.multiTenancy(c -> c.enabled(enableMt))
            // Additional settings not shown
            .vectorConfig(VectorConfig.text2vecTransformers())
            .generativeModule(Generative.cohere())
            .properties(Property.text("review_body"), Property.text("title"),
                Property.text("country"), Property.integer("points"),
                Property.number("price")));

    return clientIn.collections.use(collectionName);
  }

  void createTenantToCollection() throws IOException {
    createCollection(clientTgt, "WineReview", false);
  }
```

**C#**

```csharp
private static async Task<CollectionClient> CreateCollection(
    WeaviateClient clientIn,
    string collectionName,
    bool enableMt
)
{
    return await clientIn.Collections.Create(
        new CollectionCreateParams
        {
            Name = collectionName,
            MultiTenancyConfig = new MultiTenancyConfig { Enabled = enableMt },
            VectorConfig = Configure.Vector("default", v => v.Text2VecTransformers()),
            Properties =
            [
                Property.Text("review_body"),
                Property.Text("title"),
                Property.Text("country"),
                Property.Int("points"),
                Property.Number("price"),
            ],
        }
    );
}

private async Task CreateTenantToCollection()
{
    await CreateCollection(clientTgt, "WineReview", false);
}
```

#### Step 2: Migrate the data

Migrate:

- The `source tenant` data from `source collection` in the `client_src` instance
- to `target collection` in the `client_tgt` instance

**Python**

```py
def migrate_data(collection_src: Collection, collection_tgt: Collection):

    with collection_tgt.batch.fixed_size(batch_size=100) as batch:
        for q in tqdm(collection_src.iterator(include_vector=True)):
            batch.add_object(
                properties=q.properties,
                vector={
                    "default": q.vector["default"],
                },
                uuid=q.uuid
            )

    return True


reviews_src = client_src.collections.get("WineReviewMT")
reviews_src_tenant_a = reviews_src.with_tenant("tenantA")
reviews_tgt = client_tgt.collections.get("WineReview")

migrate_data(reviews_src_tenant_a, reviews_tgt)

client_src.close()
client_tgt.close()
```

**JavaScript/TypeScript**

```ts
let reviews_tgt, reviews_src;

let maxItems = await reviews_src.length()
let counter: number = 0

async function migrateData(collection_src: Collection, collection_tgt: Collection) {
    let itemsToInsert = []
    const promises = []

    for await (const item of collection_src.iterator({ includeVector: true })) {
        // Check if we've reached the maximum items
        if (counter >= maxItems) {
            console.log(`Reached maximum items limit of ${maxItems}`);
            break;
        }

        counter++;
        if (counter % 500 == 0)
            console.log(`Import: ${counter}`)

        let objectToInsert = {
            properties: item.properties,
            vectors: item.vectors.default,
            uuid: item.uuid,
        }

        // Add object to batching array
        itemsToInsert.push(objectToInsert)

        if (itemsToInsert.length == 500 || counter == maxItems) {
            try {
                const response = await collection_tgt.data.insertMany(itemsToInsert);

                if (response.hasErrors) {
                    throw new Error("Error in batch import!");
                }

                console.log(`Successfully imported batch of ${itemsToInsert.length} items`);
                itemsToInsert = [];
            } catch (error) {
                console.error('Error importing batch:', error);
            }
        }
    }
   
}

let reviews_src_tenant_a;

reviews_src = client_src.collections.use("WineReviewMT")
reviews_src_tenant_a = reviews_src.withTenant("tenantA")
reviews_tgt = client_tgt.collections.use("WineReview")

migrateData(reviews_src_tenant_a, reviews_tgt)

client_src.close()
client_tgt.close()
```

**Java**

```java
  private void migrateData(CollectionHandle<Map<String, Object>> collectionSrc,
      CollectionHandle<Map<String, Object>> collectionTgt) {
    System.out.println("Starting data migration...");
    List<WeaviateObject<Map<String, Object>>> sourceObjects = StreamSupport
        .stream(collectionSrc.paginate(p -> p.includeVector()).spliterator(),
            false)
        .map(readObj -> WeaviateObject
            .<Map<String, Object>>of(c -> c.properties(readObj.properties())
                .uuid(readObj.uuid())
                .vectors(readObj.vectors())))
        .collect(Collectors.toList());

    collectionTgt.data.insertMany(sourceObjects);

    System.out.println("Data migration complete.");
  }

  void testTenantToCollection() throws IOException {
    createTenantToCollection();

    var reviewsSrc = clientSrc.collections.use("WineReviewMT");
    var reviewsTgt = clientTgt.collections.use("WineReview");
    var reviewsSrcTenantA = reviewsSrc.withTenant("tenantA");
    migrateData(reviewsSrcTenantA, reviewsTgt);

  }
```

**C#**

```csharp
private async Task MigrateData<T>(
    CollectionClient collectionSrc,
    CollectionClient collectionTgt
)
{
    Console.WriteLine("Starting data migration...");

    // Fetch source objects
    var response = await collectionSrc.Query.FetchObjects(limit: 10000, includeVectors: true);

    // Map to Strong Type List
    var sourceObjects = new List<T>();
    foreach (var obj in response.Objects)
    {
        // Deserialize the inner properties Dictionary to the POCO type
        var json = JsonSerializer.Serialize(obj.Properties);
        var typedObj = JsonSerializer.Deserialize<T>(json);
        if (typedObj != null)
        {
            sourceObjects.Add(typedObj);
        }
    }

    // InsertMany using Strong Types
    await collectionTgt.Data.InsertMany(sourceObjects.ToArray());

    Console.WriteLine($"Data migration complete. Migrated {sourceObjects.Count} objects.");
}

public async Task TestTenantToCollection()
{
    await CreateTenantToCollection();

    var reviewsSrc = clientSrc.Collections.Use("WineReviewMT");
    var reviewsTgt = clientTgt.Collections.Use("WineReview");
    var reviewsSrcTenantA = reviewsSrc.WithTenant("tenantA");

    await MigrateData<WineReviewModel>(reviewsSrcTenantA, reviewsTgt);

}
```

## Tenant → Tenant

#### Step 1: Create the target collection(s)

Create a collection (e.g. `WineReview`) at the target instance, matching the collection (e.g. `WineReview`) at the source instance including enabling multi-tenancy.

**Python**

```py
import weaviate
import weaviate.classes as wvc
from weaviate.collections import Collection
from weaviate.client import WeaviateClient

client_src = weaviate.connect_to_local(
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

client_tgt = weaviate.connect_to_local(
    port=8090,
    grpc_port=50061,
    headers={
        "X-OpenAI-Api-Key": os.getenv("OPENAI_API_KEY")
    }
)

def create_collection(client_in: WeaviateClient, collection_name: str, enable_mt=False):

    reviews = client_in.collections.create(
        name=collection_name,
        multi_tenancy_config=wvc.config.Configure.multi_tenancy(enabled=enable_mt),
        # Additional settings not shown
    )

    return reviews


reviews_mt_tgt = create_collection(client_tgt, "WineReviewMT", enable_mt=True)
```

**JavaScript/TypeScript**

```ts
import weaviate, { Collection, WeaviateClient } from '@weaviate/node'

let client_src: WeaviateClient,client_tgt: WeaviateClient;
let reviews_mt_tgt, reviews_mt_src;

client_src = await weaviate.connectToLocal({
})

client_tgt = await weaviate.connectToLocal({
    port: 8090,
    grpcPort: 50061,
})

async function createCollection(clientIn: WeaviateClient, collectionName: string, enableMt: boolean) {
    let reviews = clientIn.collections.create({
        name: collectionName,
        multiTenancy: {
            enabled: enableMt
        },
        // Additional settings not shown
    })

    return reviews
}

reviews_mt_tgt = createCollection(client_tgt, "WineReviewMT", true)
```

**Java**

```java
  private static CollectionHandle<Map<String, Object>> createCollection(
      WeaviateClient clientIn, String collectionName, boolean enableMt)
      throws IOException {
    clientIn.collections.create(collectionName,
        col -> col.multiTenancy(c -> c.enabled(enableMt))
            // Additional settings not shown
            .vectorConfig(VectorConfig.text2vecTransformers())
            .generativeModule(Generative.cohere())
            .properties(Property.text("review_body"), Property.text("title"),
                Property.text("country"), Property.integer("points"),
                Property.number("price")));

    return clientIn.collections.use(collectionName);
  }

  void createTenants() throws IOException {
    var reviewsMtTgt = clientTgt.collections.use("WineReviewMT");

    var tenantsTgt =
        List.of(Tenant.active("tenantA"), Tenant.active("tenantB"));
    reviewsMtTgt.tenants.create(tenantsTgt);
  }
  void createTenantToTenant() throws IOException {
    createCollection(clientTgt, "WineReviewMT", true);
  }
```

**C#**

```csharp
private static async Task<CollectionClient> CreateCollection(
    WeaviateClient clientIn,
    string collectionName,
    bool enableMt
)
{
    return await clientIn.Collections.Create(
        new CollectionCreateParams
        {
            Name = collectionName,
            MultiTenancyConfig = new MultiTenancyConfig { Enabled = enableMt },
            VectorConfig = Configure.Vector("default", v => v.Text2VecTransformers()),
            Properties =
            [
                Property.Text("review_body"),
                Property.Text("title"),
                Property.Text("country"),
                Property.Int("points"),
                Property.Number("price"),
            ],
        }
    );
}

private async Task CreateTenants()
{
    var reviewsMtTgt = clientTgt.Collections.Use("WineReviewMT");

    var tenantsTgt = new[]
    {
        new Tenant { Name = "tenantA" },
        new Tenant { Name = "tenantB" },
    };
    await reviewsMtTgt.Tenants.Create(tenantsTgt);
}

private async Task CreateTenantToTenant()
{
    await CreateCollection(clientTgt, "WineReviewMT", true);
}
```

#### Step 2: Create the tenant(s)

Add tenants at the target instance before adding data objects.

**Python**

```py
tenants_tgt = [wvc.tenants.Tenant(name="tenantA"), wvc.tenants.Tenant(name="tenantB")]

reviews_mt_tgt = client_tgt.collections.get("WineReviewMT")
reviews_mt_tgt.tenants.create(tenants_tgt)
```

**JavaScript/TypeScript**

```ts
let tenantsTgt = [
    { name: 'tenantA'},
    { name: 'tenantB'}
  ]

reviews_mt_tgt = client_tgt.collections.use("WineReviewMT")
reviews_mt_tgt.tenants.create(tenantsTgt)
```

**Java**

```java
  void createTenants() throws IOException {
    var reviewsMtTgt = clientTgt.collections.use("WineReviewMT");

    var tenantsTgt =
        List.of(Tenant.active("tenantA"), Tenant.active("tenantB"));
    reviewsMtTgt.tenants.create(tenantsTgt);
  }
```

**C#**

```csharp
private async Task CreateTenants()
{
    var reviewsMtTgt = clientTgt.Collections.Use("WineReviewMT");

    var tenantsTgt = new[]
    {
        new Tenant { Name = "tenantA" },
        new Tenant { Name = "tenantB" },
    };
    await reviewsMtTgt.Tenants.Create(tenantsTgt);
}
```

#### Step 3: Migrate the data

Migrate:

- The `source tenant` data from `source collection` in the `client_src` instance
- to `target tenant` data from `target collection` in the `client_tgt` instance

**Python**

```py
def migrate_data(collection_src: Collection, collection_tgt: Collection):

    with collection_tgt.batch.fixed_size(batch_size=100) as batch:
        for q in tqdm(collection_src.iterator(include_vector=True)):
            batch.add_object(
                properties=q.properties,
                vector={
                    "default": q.vector["default"],
                },
                uuid=q.uuid
            )

    return True


reviews_mt_src = client_src.collections.get("WineReviewMT")
reviews_src_tenant_a = reviews_mt_src.with_tenant("tenantA")
reviews_mt_tgt = client_tgt.collections.get("WineReviewMT")
reviews_tgt_tenant_a = reviews_mt_tgt.with_tenant(tenants_tgt[0].name)

migrate_data(reviews_src_tenant_a, reviews_tgt_tenant_a)

client_src.close()
client_tgt.close()
```

**JavaScript/TypeScript**

```ts
import weaviate, { Collection, WeaviateClient } from '@weaviate/node'

let client_src: WeaviateClient,client_tgt: WeaviateClient;
let reviews_mt_tgt, reviews_mt_src;

let maxItems = await reviews_src.length()
let counter: number = 0

async function migrateData(collection_src: Collection, collection_tgt: Collection) {
    let itemsToInsert = []
    const promises = []

    for await (const item of collection_src.iterator({ includeVector: true })) {
        // Check if we've reached the maximum items
        if (counter >= maxItems) {
            console.log(`Reached maximum items limit of ${maxItems}`);
            break;
        }

        counter++;
        if (counter % 500 == 0)
            console.log(`Import: ${counter}`)

        let objectToInsert = {
            properties: item.properties,
            vectors: item.vectors.default,
            uuid: item.uuid,
        }

        // Add object to batching array
        itemsToInsert.push(objectToInsert)

        if (itemsToInsert.length == 500 || counter == maxItems) {
            try {
                const response = await collection_tgt.data.insertMany(itemsToInsert);

                if (response.hasErrors) {
                    throw new Error("Error in batch import!");
                }

                console.log(`Successfully imported batch of ${itemsToInsert.length} items`);
                itemsToInsert = [];
            } catch (error) {
                console.error('Error importing batch:', error);
            }
        }
    }
   
}
// Variables initialized above
reviews_mt_src = client_src.collections.use("WineReviewMT")
reviews_src_tenant_a = reviews_mt_src.withTenant("tenantA")
reviews_mt_tgt = client_tgt.collections.use("WineReviewMT")
reviews_tgt_tenant_a = reviews_mt_tgt.withTenant(tenantsTgt[0].name)

migrateData(reviews_src_tenant_a, reviews_tgt_tenant_a)

client_src.close()
client_tgt.close()
```

**Java**

```java
  private void migrateData(CollectionHandle<Map<String, Object>> collectionSrc,
      CollectionHandle<Map<String, Object>> collectionTgt) {
    System.out.println("Starting data migration...");
    List<WeaviateObject<Map<String, Object>>> sourceObjects = StreamSupport
        .stream(collectionSrc.paginate(p -> p.includeVector()).spliterator(),
            false)
        .map(readObj -> WeaviateObject
            .<Map<String, Object>>of(c -> c.properties(readObj.properties())
                .uuid(readObj.uuid())
                .vectors(readObj.vectors())))
        .collect(Collectors.toList());

    collectionTgt.data.insertMany(sourceObjects);

    System.out.println("Data migration complete.");
  }

  void testTenantToTenant() throws IOException {
    createTenantToTenant();
    createTenants();

    var reviewsMtSrc = clientSrc.collections.use("WineReviewMT");
    var reviewsMtTgt = clientTgt.collections.use("WineReviewMT");
    var reviewsSrcTenantA = reviewsMtSrc.withTenant("tenantA");
    var reviewsTgtTenantA = reviewsMtTgt.withTenant("tenantA");

    migrateData(reviewsSrcTenantA, reviewsTgtTenantA);

  }
```

**C#**

```csharp
private async Task MigrateData<T>(
    CollectionClient collectionSrc,
    CollectionClient collectionTgt
)
{
    Console.WriteLine("Starting data migration...");

    // Fetch source objects
    var response = await collectionSrc.Query.FetchObjects(limit: 10000, includeVectors: true);

    // Map to Strong Type List
    var sourceObjects = new List<T>();
    foreach (var obj in response.Objects)
    {
        // Deserialize the inner properties Dictionary to the POCO type
        var json = JsonSerializer.Serialize(obj.Properties);
        var typedObj = JsonSerializer.Deserialize<T>(json);
        if (typedObj != null)
        {
            sourceObjects.Add(typedObj);
        }
    }

    // InsertMany using Strong Types
    await collectionTgt.Data.InsertMany(sourceObjects.ToArray());

    Console.WriteLine($"Data migration complete. Migrated {sourceObjects.Count} objects.");
}

public async Task TestTenantToTenant()
{
    await CreateTenantToTenant();
    await CreateTenants();

    var reviewsMtSrc = clientSrc.Collections.Use("WineReviewMT");
    var reviewsMtTgt = clientTgt.Collections.Use("WineReviewMT");
    var reviewsSrcTenantA = reviewsMtSrc.WithTenant("tenantA");
    var reviewsTgtTenantA = reviewsMtTgt.WithTenant("tenantA");

    await MigrateData<WineReviewModel>(reviewsSrcTenantA, reviewsTgtTenantA);
}
```

## Related pages

- [Connect to Weaviate](https://docs.weaviate.io/weaviate/connections)
- [Cursor API](https://docs.weaviate.io/weaviate/manage-objects/read-all-objects)
- [Multi-tenancy operations](https://docs.weaviate.io/weaviate/manage-collections/multi-tenancy)
