:::callout{intent="warning" title="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.
:::

Use cross-references to establish directional relationships between collections.

:::accordion{title="Additional information"}
Notes:

- Cross-references does not affect object vectors of the source or the target objects.
- For multi-tenancy collection, you can establish a cross-reference from a multi-tenancy collection object to:
  - A non-multi-tenancy collection object, or
  - A multi-tenancy collection object belonging to the same tenant.
:::

## Define a cross-reference property

Include the reference property in the collection definition before adding cross-references to it.

:::code-group{sync="languages"}
```python title="Python" {10-15}
from weaviate.classes.config import Property, DataType, ReferenceProperty

client.collections.create(
    name="JeopardyQuestion",
    description="A Jeopardy! question",
    properties=[
        Property(name="question", data_type=DataType.TEXT),
        Property(name="answer", data_type=DataType.TEXT),
    ],
    references=[
        ReferenceProperty(
            name="hasCategory",
            target_collection="JeopardyCategory"
        )
    ]

)
```

```typescript title="JavaScript/TypeScript" {7-10}
await client.collections.create({
  name: 'JeopardyQuestion',
  properties: [
        { name: 'question' , dataType: 'text' },
        { name: 'answer', dataType: 'text' }
      ],
  references: [{
    name: 'hasCategory',
    targetCollection: 'JeopardyCategory',
  }]
})
```

```java title="Java" {8}
client.collections.create("JeopardyCategory",
    col -> col.description("A Jeopardy! category")
        .properties(Property.text("title")));

client.collections.create("JeopardyQuestion",
    col -> col.description("A Jeopardy! question")
        .properties(Property.text("question"), Property.text("answer"))
        .references(ReferenceProperty.to("hasCategory", "JeopardyCategory"))
);
```

```csharp title="C#" {16}
await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "JeopardyCategory",
        Description = "A Jeopardy! category",
        Properties = [Property.Text("title")],
    }
);

await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "JeopardyQuestion",
        Description = "A Jeopardy! question",
        Properties = [Property.Text("question"), Property.Text("answer")],
        References = [new Reference("hasCategory", "JeopardyCategory")],
    }
);
```
:::

## Add a cross-reference property

It is also possible to add a cross-reference property to an existing collection definition.

:::code-group{sync="languages"}
```python title="Python" {7-10}
from weaviate.classes.config import ReferenceProperty

# Add the reference to JeopardyQuestion, after it was created
category = client.collections.use("JeopardyCategory")
# category.config.add_reference(
category.config.add_reference(
    ReferenceProperty(
        name="hasQuestion",
        target_collection="JeopardyQuestion"
    )
)
```

```typescript title="JavaScript/TypeScript" {4-7}
// Add the "hasQuestion" cross-reference property to the JeopardyCategory collection
const category = client.collections.use('JeopardyCategory')

await category.config.addReference({
  name: 'hasQuestion',
  targetCollection: 'JeopardyQuestion'
})
```

```java title="Java" {3}
var category = client.collections.use("JeopardyCategory");
category.config.addReference(
    "hasQuestion", "JeopardyQuestion"
);
```

```csharp title="C#" {3}
var category = client.Collections.Use("JeopardyCategory");
await category.Config.AddReference(
    Property.Reference("hasQuestion", "JeopardyQuestion")
);
```
:::

## Create an object with a cross-reference

Specify a cross-reference when creating an object.

:::code-group{sync="languages"}
```python title="Python" {6}
questions = client.collections.use("JeopardyQuestion")

questions.data.insert(
    properties=properties,  # A dictionary with the properties of the object
    uuid=obj_uuid,  # The UUID of the object
    references={"hasCategory": category_uuid},  # e.g. {"hasCategory": "583876f3-e293-5b5b-9839-03f455f14575"}
)
```

```typescript title="JavaScript/TypeScript" {7-9}
const category = client.collections.use('JeopardyCategory')

const dataObject = {'name': 'Science'}

const response = await category.data.insert({
  properties: dataObject,
  references: {
    'hasCategory': categoryId  // e.g. {'hasCategory': '583876f3-e293-5b5b-9839-03f455f14575'}
  }
})

console.log('UUID: ', response)
```

```java title="Java" {5-6}
var questions = client.collections.use("JeopardyQuestion");

var result = questions.data.insert(properties, // A map with the properties of the object
    opt -> opt
        .reference("hasCategory", ObjectReference.uuids(categoryUuid)) // e.g. {"hasCategory":
// "583876f3-e293-5b5b-9839-03f455f14575"}
);
```

```csharp title="C#" {5}
var questions = client.Collections.Use("JeopardyQuestion");

var newObject = await questions.Data.Insert(
    properties, // The properties of the object
    references: [new ObjectReference("hasCategory", categoryUuid)]
);
```
:::

## Add a one-way cross-reference

Specify the required id and properties for the source and the target.

:::code-group{sync="languages"}
```python title="Python" {6}
questions = client.collections.use("JeopardyQuestion")

questions.data.reference_add(
    from_uuid=question_obj_id,
    from_property="hasCategory",
    to=category_obj_id
)
```

```typescript title="JavaScript/TypeScript" {3-7}
const jeopardy = client.collections.use('JeopardyCategory')

await jeopardy.data.referenceAdd({
  fromProperty: 'hasCategory',
  fromUuid: questionObjectId,
  to: categoryObjectId,
})
```

```go title="Go"
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"

client.Data().ReferenceCreator().
  WithClassName("JeopardyQuestion").
  WithID(sfID).
  WithReferenceProperty("hasCategory").
  WithReference(client.Data().ReferencePayloadBuilder().
    WithClassName("JeopardyCategory").
    WithID(usCitiesID).
    Payload()).
  Do(ctx)
```

```java title="Java" {2}
questions.data.referenceAdd(questionObjId, "hasCategory",
    ObjectReference.uuids(categoryObjId)[0]
);
```

```csharp title="C#" {4}
await questions.Data.ReferenceAdd(
    from: questionObjId,
    fromProperty: "hasCategory",
    to: categoryObjId
);
```
:::

## Add two-way cross-references

This requires adding reference properties in both directions, and adding two cross-references per object pair (`from` A -> `to` B and `from` B -> `to` A).

Create the `JeopardyCategory` collection:

:::code-group{sync="languages"}
```python title="Python"
from weaviate.classes.config import Property, DataType, ReferenceProperty

category = client.collections.create(
    name="JeopardyCategory",
    description="A Jeopardy! category",
    properties=[
        Property(name="title", data_type=DataType.TEXT)
    ]
)
```

```typescript title="JavaScript/TypeScript"
const category = client.collections.create({
  name: "JeopardyCategory",
  description: "A Jeopardy! category",
  properties: [
    { name: "title", dataType: "text" }
  ]
})
```

```java title="Java"
client.collections.create("JeopardyCategory",
    col -> col.description("A Jeopardy! category")
        .properties(Property.text("title")));
```

```csharp title="C#"
await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "JeopardyCategory",
        Description = "A Jeopardy! category",
        Properties = [Property.Text("title")],
    }
);
```
:::

Create the `JeopardyQuestion` collection including the reference property to `JeopardyCategory`:

:::code-group{sync="languages"}
```python title="Python" {8-13}
client.collections.create(
    name="JeopardyQuestion",
    description="A Jeopardy! question",
    properties=[
        Property(name="question", data_type=DataType.TEXT),
        Property(name="answer", data_type=DataType.TEXT),
    ],
    references=[
        ReferenceProperty(
            name="hasCategory",
            target_collection="JeopardyCategory"
        )
    ]
)
```

```typescript title="JavaScript/TypeScript" {7-10}
const jeopardyQuestionCollection = client.collections.create({
  name: 'JeopardyQuestion',
  properties: [
    { name: 'question' , dataType: 'text' },
    { name: 'answer', dataType: 'text' }
  ],
  references: [{
    name: 'hasCategory',
    targetCollection: 'JeopardyCategory'
  }]
})
```

```java title="Java" {4}
client.collections.create("JeopardyQuestion",
    col -> col.description("A Jeopardy! question")
        .properties(Property.text("question"), Property.text("answer"))
        .references(ReferenceProperty.to("hasCategory", "JeopardyCategory"))
);
```

```csharp title="C#" {7}
await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "JeopardyQuestion",
        Description = "A Jeopardy! question",
        Properties = [Property.Text("question"), Property.Text("answer")],
        References = [new Reference("hasCategory", "JeopardyCategory")],
    }
);
```
:::

Modify `JeopardyCategory` to add the reference to `JeopardyQuestion`:

:::code-group{sync="languages"}
```python title="Python" {7-10}
from weaviate.classes.config import ReferenceProperty

# Add the reference to JeopardyQuestion, after it was created
category = client.collections.use("JeopardyCategory")
# category.config.add_reference(
category.config.add_reference(
    ReferenceProperty(
        name="hasQuestion",
        target_collection="JeopardyQuestion"
    )
)
```

```typescript title="JavaScript/TypeScript" {4-7}
// Add the "hasQuestion" cross-reference property to the JeopardyCategory collection
const category = client.collections.use('JeopardyCategory')

await category.config.addReference({
  name: 'hasQuestion',
  targetCollection: 'JeopardyQuestion'
})
```

```java title="Java" {3}
var category = client.collections.use("JeopardyCategory");
category.config.addReference(
    "hasQuestion", "JeopardyQuestion"
);
```

```csharp title="C#" {3}
var category = client.Collections.Use("JeopardyCategory");
await category.Config.AddReference(
    Property.Reference("hasQuestion", "JeopardyQuestion")
);
```
:::

And add the cross-references:

:::code-group{sync="languages"}
```python title="Python" {3-7,11-15}
# For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
questions = client.collections.use("JeopardyQuestion")
questions.data.reference_add(
    from_uuid=question_obj_id,
    from_property="hasCategory",
    to=category_obj_id
)

# For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
categories = client.collections.use("JeopardyCategory")
categories.data.reference_add(
    from_uuid=category_obj_id,
    from_property="hasQuestion",
    to=question_obj_id
)
```

```typescript title="JavaScript/TypeScript" {4-8,13-17}
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
const questions = client.collections.use("JeopardyQuestion")

await questions.data.referenceAdd({
    fromUuid: questionObjectId,
    fromProperty: 'hasCategory',
    to: catogoryObjectId
})

// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
const category = client.collections.use("JeopardyCategory")

await category.data.referenceAdd({
    fromUuid: catogoryObjectId,
    fromProperty: 'hasQuestion',
    to: questionObjectId
})
```

```go title="Go"
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"
```

```java title="Java" {3-4,8-9}
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the
// "U.S. CITIES" JeopardyCategory object
questions.data.referenceAdd(questionObjId, "hasCategory",
    ObjectReference.uuids(categoryObjId)[0]);

// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San
// Francisco"
categories.data.referenceAdd(categoryObjId, "hasQuestion",
    ObjectReference.uuids(questionObjId)[0]);
```

```csharp title="C#" {2-6,9-13}
// For the "San Francisco" JeopardyQuestion object, add a cross-reference to the "U.S. CITIES" JeopardyCategory object
await questions.Data.ReferenceAdd(
    from: questionObjId,
    fromProperty: "hasCategory",
    to: categoryObjId
);

// For the "U.S. CITIES" JeopardyCategory object, add a cross-reference to "San Francisco"
await categories.Data.ReferenceAdd(
    from: categoryObjId,
    fromProperty: "hasQuestion",
    to: questionObjId
);
```
:::

## Add multiple (one-to-many) cross-references

Weaviate allows creation of multiple cross-references from one source object.

:::code-group{sync="languages"}
```python title="Python" {5-14}
from weaviate.classes.data import DataReference

questions = client.collections.use("JeopardyQuestion")

refs_list = []
for temp_uuid in [category_obj_id, category_obj_id_alt]:
    ref_obj = DataReference(
        from_uuid=question_obj_id,
        from_property="hasCategory",
        to_uuid=temp_uuid
    )
    refs_list.append(ref_obj)

questions.data.reference_add_many(refs_list)
```

```typescript title="JavaScript/TypeScript" {3}
const questions = client.collections.use("JeopardyQuestion")

await questions.data.referenceAddMany(
  [{
    fromUuid: questionObjectId,
    fromProperty: 'hasCategory',
    to: catogoryObjectId1
  },{
    fromUuid: questionObjectId,
    fromProperty: 'hasCategory',
    to: catogoryObjectId2
  }]
)
```

```go title="Go"
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
usCitiesID := "20ffc68d-986b-5e71-a680-228dba18d7ef"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"

// Add to "San Francisco" the "U.S. CITIES" category
client.Data().ReferenceCreator().
  WithClassName("JeopardyQuestion").
  WithID(sfID).
  WithReferenceProperty("hasCategory").
  WithReference(client.Data().ReferencePayloadBuilder().
    WithClassName("JeopardyCategory").
    WithID(usCitiesID).
    Payload()).
  Do(ctx)

// Add the "MUSEUMS" category as well
client.Data().ReferenceCreator().
  WithClassName("JeopardyQuestion").
  WithID(sfID).
  WithReferenceProperty("hasCategory").
  WithReference(client.Data().ReferencePayloadBuilder().
    WithClassName("JeopardyCategory").
    WithID(museumsID).
    Payload()).
  Do(ctx)
```

```java title="Java" {1-5}
// Add multiple references - need to add them individually
for (String tempUuid : List.of(categoryObjId, categoryObjIdAlt)) {
  questions.data.referenceAdd(questionObjId, "hasCategory",
      ObjectReference.uuids(tempUuid)[0]);
}
```

```csharp title="C#" {1-9}
// Add multiple references - need to add them individually
foreach (var tempUuid in new[] { categoryObjId, categoryObjIdAlt })
{
    await questions.Data.ReferenceAdd(
        from: questionObjId,
        fromProperty: "hasCategory",
        to: tempUuid
    );
}
```
:::

## Read cross-references

Cross-references can be read as part of the object.

:::code-group{sync="languages"}
```python title="Python" {6-12,15-21}
from weaviate.classes.query import QueryReference

questions = client.collections.use("JeopardyQuestion")

# Include the cross-references in a query response
response = questions.query.fetch_objects(  # Or `hybrid`, `near_text`, etc.
    limit=2,
    return_references=QueryReference(
        link_on="hasCategory",
        return_properties=["title"]
    )
)

# Or include cross-references in a single-object retrieval
obj = questions.query.fetch_object_by_id(
    uuid=question_obj_id,
    return_references=QueryReference(
        link_on="hasCategory",
        return_properties=["title"]
    )
)
```

```typescript title="JavaScript/TypeScript" {5-8}
const questions = client.collections.use("JeopardyQuestion")

const response = await questions.query.fetchObjects({ // Or `hybrid`, `nearText`, etc.
  limit: 2,
  returnReferences: [{
    linkOn: 'hasCategory',
    returnProperties: ['title']
  }]
})

response.objects.forEach(item =>
  console.log(JSON.stringify(item.references, null, 2))
)
```

```java title="Java" {2-5,8-10}
// Include the cross-references in a query response
var response = questions.query.fetchObjects( // Or `hybrid`, `nearText`, etc.
    opt -> opt.limit(2)
        .returnReferences(QueryReference.single("hasCategory",
            ref -> ref.returnProperties("title"))));

// Or include cross-references in a single-object retrieval
var obj = questions.query.fetchObjectById(questionObjId,
    opt -> opt.returnReferences(QueryReference.single("hasCategory",
        ref -> ref.returnProperties("title"))));
```

```csharp title="C#" {2-5,8-11}
// Include the cross-references in a query response
var response = await questions.Query.FetchObjects( // Or `Hybrid`, `NearText`, etc.
    limit: 2,
    returnReferences: [new QueryReference("hasCategory", fields: ["title"])]
);

// Or include cross-references in a single-object retrieval
var obj = await questions.Query.FetchObjectByID(
    questionObjId,
    returnReferences: [new QueryReference("hasCategory", fields: ["title"])]
);
```
:::

## Delete a cross-reference

Deleting a cross-reference with the same parameters used to define the cross-reference.

:::code-group{sync="languages"}
```python title="Python" {3}
# From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
questions = client.collections.use("JeopardyQuestion")
questions.data.reference_delete(
    from_uuid=question_obj_id,
    from_property="hasCategory",
    to=category_obj_id
)
```

```typescript title="JavaScript/TypeScript" {4}
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
const questions = client.collections.use("JeopardyQuestion")

await questions.data.referenceDelete({
  fromUuid: questionObjectId,
  fromProperty: 'hasCategory',
  to: catogoryObjectId
})
```

```go title="Go"
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"

// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
client.Data().ReferenceDeleter().
  WithClassName("JeopardyQuestion").
  WithID(sfID).
  WithReferenceProperty("hasCategory").
  WithReference(client.Data().ReferencePayloadBuilder().
    WithClassName("JeopardyCategory").
    WithID(museumsID).
    Payload()).
  Do(ctx)
```

```java title="Java" {3}
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS"
// category cross-reference
questions.data.referenceDelete(
    questionObjId, "hasCategory", ObjectReference.uuids(categoryObjId)[0]);
```

```csharp title="C#" {2}
// From the "San Francisco" JeopardyQuestion object, delete the "MUSEUMS" category cross-reference
await questions.Data.ReferenceDelete(
    from: questionObjId,
    fromProperty: "hasCategory",
    to: categoryObjId
);
```
:::

:::accordion{title="What happens if the target object is deleted?"}
What happens if the `to` object is deleted?
If an object is deleted, cross-references to it will be left intact. A [Get query using the inline fragment syntax](../how-to-query-search/basics.md#retrieve-cross-referenced-properties) will correctly retrieve only fields in the existing cross-references objects, but [getting the object by ID](../how-to-manage-objects/read.md#get-an-object-by-id) will show all cross-references, whether the objects they point to exist or not.
:::

## Update a cross-reference

The targets of a cross-reference can be updated.

:::code-group{sync="languages"}
```python title="Python" {3}
# In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
questions = client.collections.use("JeopardyQuestion")
questions.data.reference_replace(
    from_uuid=question_obj_id,
    from_property="hasCategory",
    to=category_obj_id
)
```

```typescript title="JavaScript/TypeScript" {4}
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
const questions = client.collections.use("JeopardyQuestion")

await questions.data.referenceReplace({
  fromUuid: questionObjectId,
  fromProperty: 'hasCategory',
  to: catogoryObjectId
})
```

```go title="Go"
sfID := "00ff6900-e64f-5d94-90db-c8cfa3fc851b"
museumsID := "fec50326-dfa1-53c9-90e8-63d0240bd933"

// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
client.Data().ReferenceReplacer().
  WithClassName("JeopardyQuestion").
  WithID(sfID).
  WithReferenceProperty("hasCategory").
  WithReferences(&models.MultipleRef{
    client.Data().ReferencePayloadBuilder().
      WithClassName("JeopardyCategory").
      WithID(museumsID).
      Payload(),
  }).
  Do(ctx)
```

```java title="Java" {3}
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory"
// cross-reference only to "MUSEUMS"
questions.data.referenceReplace(
    questionObjId, "hasCategory", ObjectReference.uuids(categoryObjId)[0]);
```

```csharp title="C#" {2}
// In the "San Francisco" JeopardyQuestion object, set the "hasCategory" cross-reference only to "MUSEUMS"
await questions.Data.ReferenceReplace(
    from: questionObjId,
    fromProperty: "hasCategory",
    to: [categoryObjId]
);
```
:::

## Related pages

- [Connect to Weaviate](../connect-to-weaviate/index.md)
- [References: REST - /v1/objects](/weaviate/api/rest#tag/objects)
- [Retrieve the cross-reference](../how-to-query-search/basics.md#retrieve-cross-referenced-properties) as a part of a query.

## Questions and feedback

Have a question or feedback? Here's how to reach us.

::::card-grid
:::card{title="Community Forum" href="https://forum.weaviate.io/c/support" icon="messages-square"}
Ask questions and connect with other developers on our **Community forum**.
:::

:::card{title="Support" href="/guides/support-overview" icon="life-buoy"}
Weaviate Cloud user or customer? Find the right channel on the **Support page**.
:::
::::

## Related pages

- [Agents](./agents-index.md)
- [AI-assisted Weaviate code generation](./ai-assisted-vibe-coding-index.md)
- [APIs](./apis-index.md)
- [Authorization and authentication](./authorization-and-authentication-index.md)
- [Benchmarks](./benchmarks-index.md)
- [Best practices](./best-practices-index.md)
- [Client libraries](./clients-index.md)
- [Client Libraries / SDKs](./client-libraries-index.md)
- [Cloud](./cloud-index.md)
- [Cloud account management](./cloud-account-management-index.md)

# Agent Instructions

This portal answers questions programmatically. To receive a synthesized,
source-cited answer instead of crawling page by page, append the `?ask=`
query parameter to any page URL on this site:

    /guides/quickstart?ask=how+do+I+authenticate

Optional parameters:

- `&goal=<what-you-are-trying-to-do>` steers the answer toward your
  objective (e.g. `&goal=write+a+python+client`).
- `&version=<label>` scopes the answer to a mounted version when the
  portal publishes more than one.

The response is `text/markdown`: the answer followed by a `# Sources` list
of the portal pages it was grounded in. Status codes are the contract:

- `200` — the answer; `402` — the portal owner’s plan or answer credits are
  exhausted (surface this to your operator; do NOT retry); `429` — you are
  rate-limited; back off for the `Retry-After` seconds; `503` — the answer
  lane is temporarily unavailable; fall back to crawling the `.md` pages.

For the full corpus map read `llms.txt` at the site root; for the tool
surface (search + page fetch as MCP tools) see `/mcp`.
