Weaviate's integration with [Morph's API](https://docs.morphllm.com/) lets you access Morph-hosted embedding models directly from Weaviate.

[Configure a Weaviate vector index](#configure-the-vectorizer) to use a Morph embedding model, and Weaviate generates embeddings for imports and searches automatically using your Morph API key. This is the _vectorizer_.

At [import time](#data-import), Weaviate generates text object embeddings and saves them into the index. For [vector](#vector-near-text-search) and [hybrid](#hybrid-search) search operations, Weaviate converts text queries into embeddings.

![Embedding integration illustration](/assets/docs/weaviate/model-providers/_includes/integration_morph_embedding.png)

:::callout{intent="warning" title="Morph lists the Embedding API as legacy"}
Morph's own documentation labels the Embedding API as legacy and planned for deprecation. Check the current status in [Morph's documentation](https://docs.morphllm.com/) before you build on this integration.
:::

## Requirements

### Weaviate configuration

Your Weaviate instance must have the `text2vec-morph` module enabled. The module is available in Weaviate `v1.32.6` and later.

:::accordion{title="For Weaviate Cloud (WCD) users"}
This integration is enabled by default on Weaviate Cloud (WCD) instances.
:::

:::accordion{title="For self-hosted users"}
- Check the [cluster metadata](../monitoring-and-logging/status.md#cluster-metadata) to verify if the module is enabled.
- Follow the [how-to configure modules](../how-to-configure-weaviate/modules.md) guide to enable the module in Weaviate.
:::

### API credentials

You must provide a Morph API key to Weaviate for this integration. Generate one in the [Morph dashboard](https://morphllm.com/) and supply it via one of:

- Set the `MORPH_APIKEY` environment variable on the Weaviate server.
- Provide the `X-Openai-Api-Key` header at request time, as shown below.

Weaviate builds Morph requests with its OpenAI-compatible client, so the request header is `X-Openai-Api-Key`. There is no Morph-specific header. A key provided in the header takes precedence over the server environment variable.

:::callout{intent="warning" title="The missing-key error names the wrong environment variable"}
When no key is available, Weaviate reports:

```
no api key found neither in request header: X-Openai-Api-Key nor in environment variable under OPENAI_APIKEY
```

The header name in that message is correct, but the environment variable name is not. This integration reads `MORPH_APIKEY`. Setting `OPENAI_APIKEY` does not make it work.
:::

:::code-group{sync="languages"}
```python title="Python"
# Recommended: save sensitive data as environment variables
morph_key = os.getenv("MORPH_APIKEY")
```

```typescript title="JavaScript/TypeScript"
const morphApiKey = process.env.MORPH_APIKEY || '';  // Replace with your inference API key
```

```java title="Java" {6-13}
// Best practice: store your credentials in environment variables
String weaviateUrl = System.getenv("WEAVIATE_URL");
String weaviateApiKey = System.getenv("WEAVIATE_API_KEY");
String morphApiKey = System.getenv("MORPH_APIKEY");

// Morph requests are built by Weaviate's OpenAI-compatible client,
// so the Morph key is supplied under the OpenAI header name.
WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl,
    weaviateApiKey,
    config -> config.setHeaders(Map.of("X-Openai-Api-Key", morphApiKey)));

System.out.println(client.isReady()); // Should print: `True`

client.close(); // Free up resources
```

```csharp title="C#" {6-18}
// Best practice: store your credentials in environment variables
string weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL");
string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY");
string morphApiKey = Environment.GetEnvironmentVariable("MORPH_APIKEY");

// Morph requests are built by Weaviate's OpenAI-compatible client,
// so the Morph key is supplied under the OpenAI header name.
using var client = await Connect.Cloud(
    weaviateUrl,
    weaviateApiKey,
    headers: new Dictionary<string, string>
    {
        ["X-Openai-Api-Key"] = morphApiKey,
    }
);

var meta = await client.GetMeta();
Console.WriteLine(meta.Version);
```
:::

:::callout{intent="note" title="One header serves two integrations"}
`X-Openai-Api-Key` is also the header for the [OpenAI integration](openai-embeddings.md). A single request therefore cannot carry different keys for the two integrations. If you use both in the same instance, set the server environment variables instead so each integration gets its own key.
:::

## Configure the vectorizer

[Configure a Weaviate index](../how-to-manage-collections/vector-config.md#specify-a-vectorizer) to use a Morph embedding model by setting the vectorizer as follows:

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

client.collections.create(
    "DemoCollection",
    vector_config=[
        Configure.Vectors.text2vec_morph(
            name="title_vector",
            source_properties=["title"],
        )
    ],
    # Additional parameters not shown
)
```

```typescript title="JavaScript/TypeScript" {9-14}
await client.collections.create({
  name: 'DemoCollection',
  properties: [
    {
      name: 'title',
      dataType: 'text' as const,
    },
  ],
  vectorizers: [
    weaviate.configure.vectors.text2VecMorph({
      name: 'title_vector',
      sourceProperties: ['title'],
    }),
  ],
  // Additional parameters not shown
});
```

```java title="Java"
client.collections.create("DemoCollection",
    col -> col
        .vectorConfig(
            VectorConfig.text2vecMorph("title_vector", c -> c.sourceProperties("title")))
        .properties(Property.text("title"), Property.text("description")));
```

```csharp title="C#"
await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "DemoCollection",
        VectorConfig = new VectorConfigList
        {
            Configure.Vector(
                "title_vector",
                v => v.Text2VecMorph(),
                sourceProperties: ["title"]
            ),
        },
        Properties = [Property.Text("title"), Property.Text("description")],
    }
);
```
:::

:::accordion{title="Vectorization behavior"}
Weaviate follows the collection configuration and a set of predetermined rules to vectorize objects.

Unless specified otherwise in the collection definition, the default behavior is to:

- Only vectorize properties that use the `text` or `text[]` data type (unless [skipped](../how-to-manage-collections/vector-config.md#property-level-settings))
- Sort properties in alphabetical (a-z) order before concatenating values
- If `vectorizePropertyName` is `true` (`false` by default) prepend the property name to each property value
- Join the (prepended) property values with spaces
- Prepend the class name (unless `vectorizeClassName` is `false`)
- Convert the produced string to lowercase

<!-- TODO: Add an actual example -->
:::

### Vectorizer parameters

- `model`: The Morph model id. Defaults to `morph-embedding-v3`.
- `baseURL`: The base URL prefix that requests are sent to. Any existing path is preserved when `endpoint` is appended. Defaults to `https://api.morphllm.com`.
- `endpoint`: The API path that Weaviate appends to the base URL. Defaults to `/v1/embeddings`. Set it if the service you target uses a different path.

For how Weaviate combines `baseURL` and `endpoint` into a request URL, see [Header parameters](#header-parameters).

:::callout{intent="info" title="`endpoint` availability"}
Added in `v1.38.2` (backported to `v1.36.19` and `v1.37.10`).
:::

Weaviate stores `baseURL` and `model` in the collection configuration even when you do not set them, because the module supplies a default for each. `endpoint` is different: it appears in the stored configuration only when you set it explicitly. If you read a collection back and see no `endpoint`, the default path applies.

No `dimensions` parameter is sent, so the embedding dimension is always the model's native size.

#### Example configuration

The following examples set the Morph-specific options. Client libraries do not all expose the same options, so each example shows what that client supports.

:::code-group{sync="languages"}
```python title="Python" {5-13}
from weaviate.classes.config import Configure

client.collections.create(
    "DemoCollection",
    vector_config=[
        Configure.Vectors.text2vec_morph(
            name="title_vector",
            source_properties=["title"],
            model="morph-embedding-v3",
            base_url="https://api.morphllm.com",  # Base URL; an existing path is preserved
            endpoint="/v1/embeddings",            # Path appended to the base URL
        )
    ],
    # Additional parameters not shown
)
```

```typescript title="JavaScript/TypeScript" {9-16}
await client.collections.create({
  name: 'DemoCollection',
  properties: [
    {
      name: 'title',
      dataType: 'text' as const,
    },
  ],
  vectorizers: [
    weaviate.configure.vectors.text2VecMorph({
      name: 'title_vector',
      sourceProperties: ['title'],
      model: 'morph-embedding-v3',
      baseURL: 'https://api.morphllm.com',  // Base URL; an existing path is preserved
    }),
  ],
  // Additional parameters not shown
});
```

```java title="Java"
client.collections.create("DemoCollection",
    col -> col
        .vectorConfig(VectorConfig.text2vecMorph("title_vector",
            c -> c.sourceProperties("title")
                .model("morph-embedding-v3")
                .baseUrl("https://api.morphllm.com") // Base URL; an existing path is preserved
                .endpoint("/v1/embeddings"))) // Path appended to the base URL
        .properties(Property.text("title"), Property.text("description")));
```

```csharp title="C#"
await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = "DemoCollection",
        VectorConfig = new VectorConfigList
        {
            Configure.Vector(
                "title_vector",
                v => v.Text2VecMorph(model: "morph-embedding-v3"),
                sourceProperties: ["title"]
            ),
        },
        Properties = [Property.Text("title"), Property.Text("description")],
    }
);
```
:::

## Header parameters

You can provide the API key and the base URL at runtime through headers. Headers provided at request time take precedence over the collection configuration and over the server environment variable:

- `X-Openai-Api-Key`: The Morph API key for this request.
- `X-Openai-Baseurl`: The base URL to use instead of the default.

Provide the headers as shown in the [API credentials examples](#api-credentials) above.

:::callout{intent="note" title="How Weaviate builds the request URL"}
Weaviate builds the request URL by appending the `endpoint` path (`/v1/embeddings` by default) to the base URL. The base URL supplies the scheme and host; `endpoint` supplies only the path. A value in `endpoint` cannot redirect requests to a different host.

If a base URL already carries a path, that path is kept and the `endpoint` path is appended to it.

There is no header that overrides `endpoint`. Set it in the collection configuration.
:::

:::callout{intent="note" title="Error messages name the OpenAI API"}
Because Weaviate uses its OpenAI-compatible client for this integration, upstream failures are reported as `connection to: OpenAI API failed with status: ...` even when the request was sent to Morph.
:::

## Data import

After configuring the vectorizer, [import data](../how-to-manage-objects/import.md) into Weaviate. Weaviate generates embeddings for text objects using [the configured model](#vectorizer-parameters).

:::callout{intent="tip" title="Re-use existing vectors"}
If you already have a compatible model vector available, you can provide it directly to Weaviate. This can be useful if you have already generated embeddings using the same model and want to use them in Weaviate, such as when migrating data from another system.
:::

## Searches

Once the vectorizer is configured, Weaviate performs vector and hybrid searches using the specified Morph model.

![Embedding integration at search illustration](/assets/docs/weaviate/model-providers/_includes/integration_morph_embedding_search.png)

### Vector (near text) search

When you perform a [vector search](../how-to-query-search/similarity.md#search-with-text), Weaviate converts the text query into an embedding using the configured Morph model and returns the most similar objects.

### Hybrid search

When you perform a [hybrid search](../how-to-query-search/hybrid.md), Weaviate fuses keyword and vector ranking. The text query is embedded with the configured Morph model; the keyword side uses Weaviate's inverted index.

## References

### Available models

Weaviate does not restrict which model id you can set, so any model the Morph API accepts can be used. `morph-embedding-v3` is the default. Morph's [list models endpoint](https://docs.morphllm.com/api-reference/endpoint/models) returns the model ids your key can use. Check it before you rely on a model id, as availability and dimensions can change.

## Further resources

### Other integrations

- [Weaviate model providers overview](index.md)

### Code examples

Once the vectorizer is configured, Weaviate handles model inference transparently. The standard [client library how-tos](../client-libraries/index.md) apply unchanged. No Morph-specific code is required at query or import time beyond the configuration shown above.

## 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`.
