This tutorial will show you how to use Weaviate Cloud to:

1. **Set up a Weaviate instance.**
2. **Import and vectorize your data.**
3. **Perform a semantic search and retrieval augmented generation (RAG).**

```mermaid
flowchart LR
    %% Define nodes with white backgrounds and darker borders
    A1["Install client<br> library"] --> A2["Connect to<br> Weaviate"]
    A2 --> B1["Define collection<br> (with an inference API)"]
    B1 --> B2["Import objects"]
    B2 --> C1["Semantic search<br> (nearText)"]
    C1 --> C2["RAG<br> (Generate)"]

    %% Group nodes in subgraphs with brand colors
    subgraph sg1 ["1\. Setup"]
        A1
        A2
    end

    subgraph sg2 ["2\. Populate"]
        B1
        B2
    end

    subgraph sg3 ["3\. Query"]
        C1
        C2
    end

    %% Style nodes with white background and darker borders
    style A1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style A2 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style B1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style B2 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style C1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style C2 fill:#ffffff,stroke:#B9C8DF,color:#130C49

    %% Style subgraphs with brand colors
    style sg1 fill:#ffffff,stroke:#61BD73,stroke-width:2px,color:#130C49
    style sg2 fill:#ffffff,stroke:#130C49,stroke-width:2px,color:#130C49
    style sg3 fill:#ffffff,stroke:#7AD6EB,stroke-width:2px,color:#130C49
```

<!-- Vectors are mathematical representations of data objects, which enable similarity-based searches in vector databases like Weaviate. -->

***

### Prerequisites

In order to perform Retrieval Augmented Generation (RAG) in the last step, you will need an [OpenAI](https://platform.openai.com/) account and an OpenAI API key.

If you have another preferred [model provider](../model-provider-integrations/index.md), you can use that instead of OpenAI.

## Step 1: Set up Weaviate

### 1.1 Install a client library

We recommend using a [client library](../client-libraries/index.md) to work with Weaviate. Follow the instructions below to install one of the official client libraries, available in [Python](../client-libraries/python.md), [JavaScript/TypeScript](../client-libraries/typescript.md), [Go](../client-libraries/go.md), and [Java](../client-libraries/java.md).

::::tabs{sync="languages"}
:::tab{title="Python"}
Install the latest, [Python client `v4`](../client-libraries/python.md), by adding `weaviate-client` to your Python environment with `pip`:

```bash
pip install -U weaviate-client
```
:::

:::tab{title="JavaScript/TypeScript"}
Install the latest, [JS/TS client `v3`](../client-libraries/typescript.md), by adding `weaviate-client` to your project with `npm`:

```bash
npm install weaviate-client
```
:::

:::tab{title="Go"}
Add `weaviate-go-client` to your project with `go get`:

```bash
go get github.com/weaviate/weaviate-go-client/v5
```
:::

:::tab{title="Java"}
Add this dependency to your project:

```xml
<dependency>
  <groupId>io.weaviate</groupId>
  <artifactId>client6</artifactId>
  <version>6.2.0</version> <!-- Check latest version: https://github.com/weaviate/java-client -->
</dependency>
```
:::

:::tab{title="C#"}
Add this package to your project:

```xml
<PackageReference Include="Weaviate.Client" Version="1.0.0" />   <!-- Check latest version: https://github.com/weaviate/java-client -->
```
:::
::::

### 1.2 Connect to Weaviate Cloud

::::accordion{title="How to create a Weaviate Cloud free cluster"}
Go to the [Weaviate Cloud console](https://console.weaviate.cloud) and create a free cluster.

[Embedded content embed](https://app.guideflow.com/embed/mk6l470aqk)

:::callout{intent="note"}
- Cluster provisioning typically takes 1-3 minutes.
- When the cluster is ready, Weaviate Cloud displays a checkmark (`✔️`) next to the cluster name.
- Note that Weaviate Cloud may add a random suffix to cluster names to ensure uniqueness.
:::

:::callout{intent="tip" title="TIP: Use the latest Weaviate version!"}
When possible, try to use the latest Weaviate version.
New releases include cutting-edge features, performance enhancements, and critical security updates to keep your application safe and up-to-date.
:::
::::

Now you can connect to your Weaviate instance. You will need the:

- **REST Endpoint URL** and the
- **Administrator API Key**.

You can retrieve them both from the [WCD console](https://console.weaviate.cloud) as shown in the interactive example below.

[Embedded content embed](https://app.guideflow.com/embed/ok8l954sxr)

:::callout{intent="info" title="REST vs gRPC endpoints"}
Weaviate supports both REST and gRPC protocols. For Weaviate Cloud deployments, you only need to provide the REST endpoint URL - the client will automatically configure gRPC.
:::

Once you have the **REST Endpoint URL** and the **admin API key**, you can connect to your cluster, and work with Weaviate.

The example below shows how to connect to Weaviate and perform a basic operation, like checking the cluster status.

:::::tabs{sync="languages"}
:::tab{title="Python"}
```python title="quickstart_check_readiness.py" {9-12}
import weaviate
from weaviate.classes.init import Auth
import os

# Best practice: store your credentials in environment variables
weaviate_url = os.environ["WEAVIATE_URL"]
weaviate_api_key = os.environ["WEAVIATE_API_KEY"]

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=weaviate_url,
    auth_credentials=Auth.api_key(weaviate_api_key),
)

print(client.is_ready())  # Should print: `True`

client.close()  # Free up resources
```
:::

:::tab{title="JavaScript/TypeScript"}
```typescript title="quickstart_check_readiness.ts" {7-12}
import weaviate, { WeaviateClient } from 'weaviate-client';

// Best practice: store your credentials in environment variables
const weaviateUrl = process.env.WEAVIATE_URL as string;
const weaviateApiKey = process.env.WEAVIATE_API_KEY as string;

const client: WeaviateClient = await weaviate.connectToWeaviateCloud(
  weaviateUrl, // Replace with your Weaviate Cloud URL
  {
    authCredentials: new weaviate.ApiKey(weaviateApiKey), // Replace with your Weaviate Cloud API key
  }
);

var clientReadiness = await client.isReady();
console.log(clientReadiness); // Should return `true`

client.close(); // Close the client connection
```
:::

::::tab{title="Go"}
```goraw title="quickstart/1_check_readiness/main.go" {17-23}
// Set these environment variables
// WEAVIATE_HOSTNAME      your Weaviate instance hostname
// WEAVIATE_API_KEY      your Weaviate instance API key

package main

import (
  "context"
  "fmt"
  "os"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/auth"
)

func main() {
  cfg := weaviate.Config{
    Host:       os.Getenv("WEAVIATE_HOSTNAME"),
    Scheme:     "https",
    AuthConfig: auth.ApiKey{Value: os.Getenv("WEAVIATE_API_KEY")},
  }

  client, err := weaviate.NewClient(cfg)
  if err != nil {
    fmt.Println(err)
  }

  // Check the connection
  ready, err := client.Misc().ReadyChecker().Do(context.Background())
  if err != nil {
    panic(err)
  }
  fmt.Printf("%v", ready)
}
```

:::callout{intent="warning"}
This client uses the `hostname` parameter (without the `https` scheme) instead of a complete `URL`.
:::
::::

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

WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl, // Replace with your Weaviate Cloud URL
    weaviateApiKey // Replace with your Weaviate Cloud key
);
System.out.println(client.isReady()); // Should print: `True`

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

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

WeaviateClient client = await Connect.Cloud(weaviateUrl, weaviateApiKey);

// GetMeta returns server info. A successful call indicates readiness.
var meta = await client.IsReady();
Console.WriteLine(meta);
```
:::

:::tab{title="Curl"}
```bash
# Best practice: store your credentials in environment variables
# export WEAVIATE_URL="YOUR_INSTANCE_URL"  # Your Weaviate instance URL
# export WEAVIATE_API_KEY="YOUR_API_KEY"   # Your Weaviate instance API key

curl -w "\nResponse code: %{http_code}\n" \
  -H "Authorization: Bearer $WEAVIATE_API_KEY" \
  $WEAVIATE_URL/v1/.well-known/ready

# You should see "Response code: 200" if the instance is ready
```
:::
:::::

If you did not see any errors, you are ready to proceed. We will replace the simple cluster status check with more meaningful operations in the next steps.

## Step 2: Populate the database

Now, we can populate our database by first defining a collection and then adding data.

### 2.1 Define a collection

:::callout{intent="info" title="What is a collection?"}
A collection is a set of objects that share the same data structure, like a table in relational databases or a collection in NoSQL databases. A collection also includes additional configurations that define how the data objects are stored and indexed.
:::

The following example creates a _collection_ called `Question` with:

- The [Weaviate Embeddings](../model-provider-integrations/weaviate-embeddings.md) service for creating vectors during ingestion & queries.

:::::tabs{sync="languages"}
::::tab{title="Python"}
:::callout{intent="warning" title=".Vectors.text2vec_xxx with AutoSchema"}
Defining a collection with `Configure.Vectors.text2vec_xxx()` with Python client library `4.16.0`-`4.16.3` will throw an error if no properties are defined and `vectorize_collection_name` is not set to `True`.

This is addressed in `4.16.4` of the Weaviate Python client. See this FAQ entry for more details: [Invalid properties error in Python client versions 4.16.0 to 4.16.3](../others/faq.md#q-invalid-properties-error-when-creating-a-collection-python-client-versions-4160-to-4163).
:::

:::callout{intent="info" title="Python and JS/TS client - Vectorizer Configuration API Changes"}
Starting with Weaviate Python client `v4.16.0`, the [vectorizer configuration API has been updated](../client-libraries/python.md#vectorizer-api-changes-v4160).\
Starting with Weaviate JS/TS client `v3.8.0`, the [vectorizer configuration API has been updated](../client-libraries/typescript.md#vectorizer-api-changes-v380).

Action required: **Update to the latest client version** and migrate your code to use the [new vectorizer configuration API](../how-to-manage-collections/vector-config.md#specify-a-vectorizer).
:::

```python title="quickstart_create_collection.py"
import weaviate
from weaviate.classes.init import Auth
from weaviate.classes.config import Configure
import os

# Best practice: store your credentials in environment variables
weaviate_url = os.environ["WEAVIATE_URL"]
weaviate_api_key = os.environ["WEAVIATE_API_KEY"]

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=weaviate_url,  # Replace with your Weaviate Cloud URL
    auth_credentials=Auth.api_key(weaviate_api_key),  # Replace with your Weaviate Cloud key
)
```
::::

:::tab{title="JavaScript/TypeScript"}
```typescript title="quickstart_create_collection.ts"
import weaviate, { WeaviateClient, vectors } from 'weaviate-client';

// Best practice: store your credentials in environment variables
const weaviateUrl = process.env.WEAVIATE_URL as string;
const weaviateApiKey = process.env.WEAVIATE_API_KEY as string;

const client: WeaviateClient = await weaviate.connectToWeaviateCloud(
  weaviateUrl, // Replace with your Weaviate Cloud URL
  {
    authCredentials: new weaviate.ApiKey(weaviateApiKey), // Replace with your Weaviate Cloud API key
  }
);
```
:::

:::tab{title="Go"}
The collection also contains a configuration for the generative (RAG) integration:

- OpenAI [generative AI integrations](../model-provider-integrations/openai-generative.md) for retrieval augmented generation (RAG).

```goraw title="quickstart/2_1_create_collection/main.go"
// Set these environment variables
// WEAVIATE_HOSTNAME      your Weaviate instance hostname
// WEAVIATE_API_KEY      your Weaviate instance API key

package main

import (
  "context"
  "fmt"
  "os"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/auth"
  "github.com/weaviate/weaviate/entities/models"
)

func main() {
  cfg := weaviate.Config{
    Host:       os.Getenv("WEAVIATE_HOSTNAME"),
    Scheme:     "https",
    AuthConfig: auth.ApiKey{Value: os.Getenv("WEAVIATE_API_KEY")},
  }

  client, err := weaviate.NewClient(cfg)
  if err != nil {
    fmt.Println(err)
  }
```
:::

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

WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl, // Replace with your Weaviate Cloud URL
    weaviateApiKey // Replace with your Weaviate Cloud key
);

String collectionName = "Question";
try { client.collections.delete(collectionName); } catch (Exception ignored) {} // Clean up from any previous run
client.collections.create(
    collectionName,
    col -> col
        .vectorConfig(VectorConfig.text2vecWeaviate()) // Configure the Weaviate Embeddings integration
        .generativeModule(Generative.openai()) // Configure the OpenAI generative AI integration
);
CollectionHandle<Map<String, Object>> questions = client.collections.use(collectionName);
```
:::

:::tab{title="C#"}
```csharp {1-14}
var questions = await client.Collections.Create(
    new CollectionCreateParams
    {
        Name = collectionName,
        Properties =
        [
            Property.Text("answer"),
            Property.Text("question"),
            Property.Text("category"),
        ],
        VectorConfig = Configure.Vector("default", v => v.Text2VecWeaviate()), // Configure the Weaviate Embeddings integration
        GenerativeConfig = Configure.Generative.OpenAI(), // Configure the OpenAI generative AI integration
    }
);
```
:::

:::tab{title="Curl"}
The collection also contains a configuration for the generative (RAG) integration:

- OpenAI [generative AI integrations](../model-provider-integrations/openai-generative.md) for retrieval augmented generation (RAG).

```bash
# Best practice: store your credentials in environment variables
# export WEAVIATE_URL="YOUR_INSTANCE_URL"  # Your Weaviate instance URL
# export WEAVIATE_API_KEY="YOUR_API_KEY"   # Your Weaviate instance API key

curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WEAVIATE_API_KEY" \
-d '{
  "class": "Question",
  "vectorizer": "text2vec-weaviate",
  "moduleConfig": {
    "text2vec-weaviate": {},
    "generative-openai": {}
  }
}' \
"$WEAVIATE_URL/v1/schema"
```
:::
:::::

Run this code to create the collection to which you can add data.

:::::accordion{title="Do you prefer a different setup?"}
If you prefer a different model provider integration, or prefer to import your own vectors, see one of the following guides:

::::card-grid
:::card{title="Prefer a different model provider?" href="/guides/model-provider-integrations-index" icon="puzzle"}
See the embedding model providers page for information on other available vectorizers, such as AWS, Cohere, Google, and many more.
:::

:::card{title="You have precomputed embeddings?" href="/guides/starter-guides-custom-vectors" icon="workflow"}
If you prefer to add custom vectors yourself along with the object data, see the Bring Your Own Vectors starter guide.
:::
::::
:::::

### 2.2 Add objects

We can now add data to our collection.

The following example:

- Loads objects, and
- Adds objects to the target collection (`Question`) with a batch import.

:::callout{intent="tip" title="Batch imports"}
Batch imports are the most efficient way to add large amounts of data, because they send objects in groups instead of one request per object. See the [How-to: Batch import](../how-to-manage-objects/import.md) guide for the available methods, including [server-side batching](../how-to-manage-objects/import.md#server-side-batching), where the server tells the client how much data to send next.
:::

Every import reports whether any objects failed. Check for failures in your own code to catch problems such as malformed data or a misconfigured model provider.

:::::tabs{sync="languages"}
:::tab{title="Python"}
```python title="quickstart_import.py" {21-30}
import weaviate
from weaviate.classes.init import Auth
import requests, json, os

# Best practice: store your credentials in environment variables
weaviate_url = os.environ["WEAVIATE_URL"]
weaviate_api_key = os.environ["WEAVIATE_API_KEY"]

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=weaviate_url,                                    # Replace with your Weaviate Cloud URL
    auth_credentials=Auth.api_key(weaviate_api_key),             # Replace with your Weaviate Cloud key
)

resp = requests.get(
    "https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json"
)
data = json.loads(resp.text)

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

result = questions.data.ingest(
    [
        {
            "answer": d["Answer"],
            "question": d["Question"],
            "category": d["Category"],
        }
        for d in data
    ]
)

# `errors` holds one entry per failed object, keyed by its position in the input
if result.errors:
    print(f"Number of failed imports: {len(result.errors)}")
    for index, error in result.errors.items():
        print(f"Failed object at index {index}: {error.message}")

client.close()  # Free up resources
```

`data.ingest()` returns a `BatchObjectReturn`. Read `result.errors` to check for failures. It holds one entry per failed object, keyed by its position in the input. For more, see [error handling in the Python client reference](../client-libraries/python-notes-best-practices.md#error-handling).
:::

:::tab{title="JavaScript/TypeScript"}
```typescript title="quickstart_import.ts" {26-29}
import weaviate, { WeaviateClient } from 'weaviate-client';

// Best practice: store your credentials in environment variables
const weaviateUrl = process.env.WEAVIATE_URL as string;
const weaviateApiKey = process.env.WEAVIATE_API_KEY as string;

const client: WeaviateClient = await weaviate.connectToWeaviateCloud(
  weaviateUrl, // Replace with your Weaviate Cloud URL
  {
    authCredentials: new weaviate.ApiKey(weaviateApiKey), // Replace with your Weaviate Cloud API key
  }
);

// Load data
async function getJsonData() {
  const file = await fetch(
    'https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json'
  );
  return file.json();
}

async function importQuestions() {
  const questions = client.collections.use('Question');
  const data = await getJsonData();

  // `ingest` imports the list using server-side batching
  const result = await questions.data.ingest(
    data.map((properties) => ({ properties }))
  );

  if (result.hasErrors) {
    console.log(`Number of failed imports: ${Object.keys(result.errors).length}`);
    // `errors` is keyed by the position of the object in the input
    for (const [index, error] of Object.entries(result.errors)) {
      console.log(`Failed object at index ${index}: ${error.message}`);
    }
  }
}

await importQuestions();

client.close(); // Close the client connection
```

`data.ingest()` returns a result object. Read `result.hasErrors` for a quick check, and `result.errors` for one entry per failed object, keyed by its position in the input.
:::

:::tab{title="Go"}
```goraw title="quickstart/2_2_import/main.go" {44-66}
// Set these environment variables
// WEAVIATE_HOSTNAME      your Weaviate instance hostname
// WEAVIATE_API_KEY      your Weaviate instance API key

package main

import (
  "context"
  "encoding/json"
  "fmt"
  "net/http"
  "os"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/auth"
  "github.com/weaviate/weaviate/entities/models"
)

func main() {
  cfg := weaviate.Config{
    Host:       os.Getenv("WEAVIATE_HOSTNAME"),
    Scheme:     "https",
    AuthConfig: auth.ApiKey{Value: os.Getenv("WEAVIATE_API_KEY")},
  }

  client, err := weaviate.NewClient(cfg)
  if err != nil {
    fmt.Println(err)
  }

  // Retrieve the data
  data, err := http.DefaultClient.Get("https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json")
  if err != nil {
    panic(err)
  }
  defer data.Body.Close()

  // Decode the data
  var items []map[string]string
  if err := json.NewDecoder(data.Body).Decode(&items); err != nil {
    panic(err)
  }

  // convert items into a slice of models.Object
  objects := make([]*models.Object, len(items))
  for i := range items {
    objects[i] = &models.Object{
      Class: "Question",
      Properties: map[string]any{
        "category": items[i]["Category"],
        "question": items[i]["Question"],
        "answer":   items[i]["Answer"],
      },
    }
  }

  // batch write items
  batchRes, err := client.Batch().ObjectsBatcher().WithObjects(objects...).Do(context.Background())
  if err != nil {
    panic(err)
  }
  for _, res := range batchRes {
    if res.Result.Errors != nil {
      panic(res.Result.Errors.Error)
    }
  }
}
```
:::

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

WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl, // Replace with your Weaviate Cloud URL
    weaviateApiKey // Replace with your Weaviate Cloud key
);

// Create the collection
String collectionName = "Question";
try { client.collections.delete(collectionName); } catch (Exception ignored) {} // Clean up from any previous run
client.collections.create(collectionName, col -> col
    .properties(
        Property.text("answer"),
        Property.text("question"),
        Property.text("category"))
    .vectorConfig(VectorConfig.text2vecWeaviate())); // Configure the Weaviate Embeddings integration;
// Get JSON data using HttpURLConnection
URL url = URI.create("https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json").toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
String jsonData;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
  jsonData = reader.lines().reduce("", String::concat);
}

CollectionHandle<Map<String, Object>> questions = client.collections.use(collectionName);
List<Map<String, Object>> questionsToInsert = new ArrayList<>();

// Parse and prepare objects using org.json
new JSONArray(jsonData).forEach(item -> {
  JSONObject json = (JSONObject) item;
  Map<String, Object> properties = new HashMap<>();
  properties.put("answer", json.getString("Answer"));
  properties.put("question", json.getString("Question"));
  properties.put("category", json.getString("Category"));
  questionsToInsert.add(properties);
});

// `batch.start()` opens a server-side batch
BatchContext<Map<String, Object>> batch = questions.batch.start();
// Closing the batch sends the remaining objects and waits for the results
try (batch) {
  for (Map<String, Object> properties : questionsToInsert) {
    batch.add(WeaviateObject.<Map<String, Object>>of(o -> o.properties(properties)));
  }
}

// Check for errors
if (batch.numberOfErrors() > 0) {
  System.err.printf("Number of failed imports: %d\n", batch.numberOfErrors());
} else {
  System.out.printf("Successfully inserted %d objects.\n", questionsToInsert.size());
}
```

`batch.start()` opens a server-side batch. Closing the batch sends any remaining objects and waits for the server to report the results. Read `batch.numberOfErrors()` after the batch closes; before then, the tally is incomplete.
:::

:::tab{title="C#"}
```csharp {7-26}
// Get JSON data using HttpClient
using var httpClient = new HttpClient();
var jsonData = await httpClient.GetStringAsync(
    "https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json"
);

var questionsToInsert = new List<object>();

// Parse and prepare objects using System.Text.Json
var jsonObjects = JsonSerializer.Deserialize<List<Dictionary<string, JsonElement>>>(
    jsonData
);
foreach (var jsonObj in jsonObjects)
{
    questionsToInsert.Add(
        new
        {
            answer = jsonObj["Answer"].GetString(),
            question = jsonObj["Question"].GetString(),
            category = jsonObj["Category"].GetString(),
        }
    );
}

// `Batch.InsertMany` imports the list using server-side batching
var insertResponse = await questions.Batch.InsertMany(questionsToInsert);

// Check for errors
if (insertResponse.HasErrors)
{
    Console.WriteLine($"Number of failed imports: {insertResponse.Errors.Count()}");
    // `Objects` holds one entry per object; `Index` is the position of the object in the input
    foreach (var entry in insertResponse.Objects.Where(o => o.Error is not null))
    {
        Console.WriteLine($"Failed object at index {entry.Index}: {entry.Error.Message}");
    }
}
else
{
    Console.WriteLine($"Successfully inserted {insertResponse.Count} objects.");
}
```

`Batch.InsertMany()` returns a `BatchInsertResponse`. Read `HasErrors` for a quick check, `Errors` for the failures alone, and `Objects` for one entry per object. Each entry's `Index` is its position in the input, and failed entries carry an `Error`.
:::

::::tab{title="Curl"}
:::callout{intent="note"}
- Download the `jeopardy_tiny.json` file from [here](https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json) before running the following script.
- This assumes you have `jq` installed.
:::

```bash
# Best practice: store your credentials in environment variables
# export WEAVIATE_URL="YOUR_INSTANCE_URL"  # Your Weaviate instance URL
# export WEAVIATE_API_KEY="YOUR_API_KEY"   # Your Weaviate instance API key

# Set batch size
BATCH_ENDPOINT="$WEAVIATE_URL/v1/batch/objects"
BATCH_SIZE=100

# Read the JSON file and loop through its entries
lines_processed=0
batch_data="{\"objects\": ["

cat jeopardy_tiny.json | jq -c '.[]' | while read line; do
  # Concatenate lines
  line=$(echo "$line" | jq "{class: \"Question\", properties: {answer: .Answer, question: .Question, category: .Category}}")
  if [ $lines_processed -eq 0 ]; then
    batch_data+=$line
  else
    batch_data+=",$line"
  fi

  lines_processed=$((lines_processed + 1))

  # If the batch is full, send it to the API using curl
  if [ $lines_processed -eq $BATCH_SIZE ]; then
    batch_data+="]}"

    curl -X POST "$BATCH_ENDPOINT" \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer $WEAVIATE_API_KEY" \
         -d "$batch_data"
    echo "" # Print a newline for better output formatting

    # Reset the batch data and counter
    lines_processed=0
    batch_data="{\"objects\": ["
  fi
done

# Send the remaining data (if any) to the API using curl
if [ $lines_processed -ne 0 ]; then
  batch_data+="]}"

  curl -X POST "$BATCH_ENDPOINT" \
       -H "Content-Type: application/json" \
       -H "Authorization: Bearer $WEAVIATE_API_KEY" \
       -d "$batch_data"
  echo "" # Print a newline for better output formatting
fi
```
::::
:::::

Run this code to add the demo data.

## Step 3: Queries

Weaviate provides a wide range of query tools to help you find the right data. We will try a few searches here.

### 3.1 Semantic search

Semantic search finds results based on meaning. This is called `nearText` in Weaviate.

The following example searches for 2 objects whose meaning is most similar to that of `biology`.

:::code-group{sync="languages"}
```python title="Python" {16-19}
import weaviate
from weaviate.classes.init import Auth
import os, json

# Best practice: store your credentials in environment variables
weaviate_url = os.environ["WEAVIATE_URL"]
weaviate_api_key = os.environ["WEAVIATE_API_KEY"]

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=weaviate_url,                                    # Replace with your Weaviate Cloud URL
    auth_credentials=Auth.api_key(weaviate_api_key),             # Replace with your Weaviate Cloud key
)

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

response = questions.query.near_text(
    query="biology",
    limit=2
)

for obj in response.objects:
    print(json.dumps(obj.properties, indent=2))

client.close()  # Free up resources
```

```typescript title="JavaScript/TypeScript" {14-18}
import weaviate, { WeaviateClient } from 'weaviate-client';

// Best practice: store your credentials in environment variables
const weaviateUrl = process.env.WEAVIATE_URL as string;
const weaviateApiKey = process.env.WEAVIATE_API_KEY as string;

const client: WeaviateClient = await weaviate.connectToWeaviateCloud(
  weaviateUrl, // Replace with your Weaviate Cloud URL
  {
    authCredentials: new weaviate.ApiKey(weaviateApiKey), // Replace with your Weaviate Cloud API key
  }
);

const questions = client.collections.use('Question');

const result = await questions.query.nearText('biology', {
  limit: 2,
});

result.objects.forEach((item) => {
  console.log(JSON.stringify(item.properties, null, 2));
});

client.close(); // Close the client connection
```

```goraw title="Go" {29-41}
// Set these environment variables
// WEAVIATE_HOSTNAME      your Weaviate instance hostname
// WEAVIATE_API_KEY      your Weaviate instance API key

package main

import (
  "context"
  "fmt"
  "os"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/auth"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
  cfg := weaviate.Config{
    Host:       os.Getenv("WEAVIATE_HOSTNAME"),
    Scheme:     "https",
    AuthConfig: auth.ApiKey{Value: os.Getenv("WEAVIATE_API_KEY")},
  }

  client, err := weaviate.NewClient(cfg)
  if err != nil {
    fmt.Println(err)
  }

  ctx := context.Background()

  response, err := client.GraphQL().Get().
    WithClassName("Question").
    WithFields(
      graphql.Field{Name: "question"},
      graphql.Field{Name: "answer"},
      graphql.Field{Name: "category"},
    ).
    WithNearText(client.GraphQL().NearTextArgBuilder().
      WithConcepts([]string{"biology"})).
    WithLimit(2).
    Do(ctx)

  if err != nil {
    panic(err)
  }
  fmt.Printf("%v", response)
}
```

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

WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl, // Replace with your Weaviate Cloud URL
    weaviateApiKey // Replace with your Weaviate Cloud key
);

String collectionName = "Question";
var questions = client.collections.use(collectionName);

var response = questions.query.nearText("biology", q -> q.limit(2));

for (var obj : response.objects()) {
  System.out.println(obj.properties());
}
```

```csharp title="C#" {1}
var response = await questions.Query.NearText("biology", limit: 2);

foreach (var obj in response.Objects)
{
    Console.WriteLine(JsonSerializer.Serialize(obj.Properties));
}
```

```bash title="Curl"
# Best practice: store your credentials in environment variables
# export WEAVIATE_URL="YOUR_INSTANCE_URL"    # Your Weaviate instance URL
# export WEAVIATE_API_KEY="YOUR_API_KEY"     # Your Weaviate instance API key

echo '{
  "query": "{
    Get {
      Question (
        limit: 2
        nearText: {
          concepts: [\"biology\"],
        }
      ) {
        question
        answer
        category
      }
    }
  }"
}' | tr -d "\n" | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $WEAVIATE_API_KEY" \
    -d @- \
    $WEAVIATE_URL/v1/graphql
```
:::

Run this code to perform the query. Our query found entries for `DNA` and `species`.

:::accordion{title="Example response"}
```json
{
  "answer": "DNA",
  "question": "In 1953 Watson & Crick built a model of the molecular structure of this, the gene-carrying substance",
  "category": "SCIENCE"
}
{
  "answer": "species",
  "question": "2000 news: the Gunnison sage grouse isn't just another northern sage grouse, but a new one of this classification",
  "category": "SCIENCE"
}
```
:::

If you inspect the full response, you will see that the word `biology` does not appear anywhere.

Even so, Weaviate was able to return biology-related entries. This is made possible by _vector embeddings_ that capture meaning. Under the hood, semantic search is powered by vectors, or vector embeddings.

Here is a diagram showing the workflow in Weaviate.

```mermaid
flowchart LR
    Query["🔍 Search:<br> 'biology'"]

    subgraph sg1 ["Vector Search"]
        direction LR
        VS1["Convert query<br> to vector"] --> VS2["Find similar<br> vectors"]
        VS2 --> VS3["Return top<br> matches"]
    end

    subgraph sg2 ["Results"]
        R1["Most similar<br> documents"]
    end

    Query --> VS1
    VS3 --> R1

    %% Style nodes with white background and darker borders
    style Query fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS2 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS3 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style R1 fill:#ffffff,stroke:#B9C8DF,color:#130C49

    %% Style subgraphs with brand colors
    style sg1 fill:#ffffff,stroke:#61BD73,stroke-width:2px,color:#130C49
    style sg2 fill:#ffffff,stroke:#130C49,stroke-width:2px,color:#130C49
```

:::callout{intent="info" title="Where did the vectors come from?"}
Weaviate used the **Weaviate Embeddings** service to generate a vector embedding for each object during import. During the query, Weaviate similarly converted the query (`biology`) into a vector.

As we mentioned above, this is optional. See [Starter Guide: Bring Your Own Vectors](../starter-guides/custom-vectors.md) if you would prefer to provide your own vectors.
:::

:::callout{intent="tip" title="More search types available"}
Weaviate is capable of many types of searches. See, for example, our how-to guides on [similarity searches](../how-to-query-search/similarity.md), [keyword searches](../how-to-query-search/bm25.md), [hybrid searches](../how-to-query-search/hybrid.md), and [filtered searches](../how-to-query-search/filters.md).
:::

### 3.2 Retrieval augmented generation

Retrieval augmented generation (RAG), also called generative search, combines the power of generative AI models such as large language models (LLMs) with the up-to-date truthfulness of a database.

RAG works by prompting a large language model (LLM) with a combination of a _user query_ and _data retrieved from a database_.

This diagram shows the RAG workflow in Weaviate.

```mermaid
flowchart LR
    subgraph sg0 ["Weaviate Query"]
        direction TB
        Search["🔍 Search:<br> 'biology'"]
        Prompt["✍️ Prompt:<br> 'Write a<br> tweet...'"]
    end

    subgraph sg1 ["Vector Search"]
        direction LR
        VS1["Convert query<br> to vector"] --> VS2["Find similar<br> vectors"]
        VS2 --> VS3["Return top<br> matches"]
    end

    subgraph sg2 ["Generation"]
        direction LR
        G1["Send<br> (results + prompt)<br> to LLM"]
        G1 --> G2["Generate<br> response"]
    end

    subgraph sg3 ["Results"]
        direction TB
        R1["Most similar<br> documents"]
        R2["Generated<br> content"]
    end

    Search --> VS1
    VS3 --> R1
    Prompt --> G1
    VS3 --> G1
    G2 --> R2

    %% Style nodes with white background and darker borders
    style Search fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style Prompt fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS2 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style VS3 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style G1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style G2 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style R1 fill:#ffffff,stroke:#B9C8DF,color:#130C49
    style R2 fill:#ffffff,stroke:#B9C8DF,color:#130C49

    %% Style subgraphs with brand colors
    style sg0 fill:#ffffff,stroke:#130C49,stroke-width:2px,color:#130C49
    style sg1 fill:#ffffff,stroke:#61BD73,stroke-width:2px,color:#130C49
    style sg2 fill:#ffffff,stroke:#7AD6EB,stroke-width:2px,color:#130C49
    style sg3 fill:#ffffff,stroke:#130C49,stroke-width:2px,color:#130C49
```

The following example combines the same search (for `biology`) with a prompt to generate a tweet.

:::code-group{sync="languages"}
```python title="Python" {17,22-27}
import os
import weaviate
from weaviate.classes.init import Auth
from weaviate.classes.generate import GenerativeConfig


# Best practice: store your credentials in environment variables
weaviate_url = os.environ["WEAVIATE_URL"]
weaviate_api_key = os.environ["WEAVIATE_API_KEY"]
openai_api_key = os.environ["OPENAI_API_KEY"]

client = weaviate.connect_to_weaviate_cloud(
    cluster_url=weaviate_url,  # Replace with your Weaviate Cloud URL
    auth_credentials=Auth.api_key(
        weaviate_api_key
    ),  # Replace with your Weaviate Cloud key
    headers={"X-OpenAI-Api-Key": openai_api_key},  # Replace with your OpenAI API key
)

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

response = questions.generate.near_text(
    query="biology",
    limit=2,
    grouped_task="Write a tweet with emojis about these facts.",
    generative_provider=GenerativeConfig.openai(),  # Configure the OpenAI generative integration for RAG
)

print(response.generative.text)  # Inspect the generated text

client.close()  # Free up resources
```

```typescript title="JavaScript/TypeScript" {12-14,18-29}
import weaviate, { WeaviateClient, generativeParameters } from 'weaviate-client';

// Best practice: store your credentials in environment variables
const weaviateUrl = process.env.WEAVIATE_URL as string;
const weaviateApiKey = process.env.WEAVIATE_API_KEY as string;
const openAiKey = process.env.OPENAI_API_KEY as string;

const client: WeaviateClient = await weaviate.connectToWeaviateCloud(
  weaviateUrl, // Replace with your Weaviate Cloud URL
  {
    authCredentials: new weaviate.ApiKey(weaviateApiKey), // Replace with your Weaviate Cloud API key
    headers: {
      'X-OpenAI-Api-Key': openAiKey, // Replace with your OpenAI API key
    },
  }
);

const questions = client.collections.use('Question');

const result = await questions.generate.nearText(
  'biology',
  {
    groupedTask: 'Write a tweet with emojis about these facts.',
    config: generativeParameters.openAI(),
  },
  {
    limit: 2,
  }
);

console.log(result.generative);

client.close(); // Close the client connection
```

```goraw title="Go" {23-25,33-50}
// Set these environment variables
// WEAVIATE_HOSTNAME      your Weaviate instance hostname
// WEAVIATE_API_KEY      your Weaviate instance API key
// OPENAI_API_KEY       your OpenAI API key

package main

import (
  "context"
  "fmt"
  "os"

  "github.com/weaviate/weaviate-go-client/v5/weaviate"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/auth"
  "github.com/weaviate/weaviate-go-client/v5/weaviate/graphql"
)

func main() {
  cfg := weaviate.Config{
    Host:       os.Getenv("WEAVIATE_HOSTNAME"),
    Scheme:     "https",
    AuthConfig: auth.ApiKey{Value: os.Getenv("WEAVIATE_API_KEY")},
    Headers: map[string]string{
      "X-OpenAI-Api-Key": os.Getenv("OPENAI_API_KEY"),
    },
  }

  client, err := weaviate.NewClient(cfg)
  if err != nil {
    fmt.Println(err)
  }

  ctx := context.Background()

  generatePrompt := "Write a tweet with emojis about these facts."

  gs := graphql.NewGenerativeSearch().GroupedResult(generatePrompt)

  response, err := client.GraphQL().Get().
    WithClassName("Question").
    WithFields(
      graphql.Field{Name: "question"},
      graphql.Field{Name: "answer"},
      graphql.Field{Name: "category"},
    ).
    WithGenerativeSearch(gs).
    WithNearText(client.GraphQL().NearTextArgBuilder().
      WithConcepts([]string{"biology"})).
    WithLimit(2).
    Do(ctx)

  if err != nil {
    panic(err)
  }
  fmt.Printf("%v", response)
}
```

```java title="Java" {6-11,15-22}
// Best practice: store your credentials in environment variables
String weaviateUrl = System.getenv("WEAVIATE_URL");
String weaviateApiKey = System.getenv("WEAVIATE_API_KEY");
String openaiApiKey = System.getenv("OPENAI_API_KEY");

WeaviateClient client = WeaviateClient.connectToWeaviateCloud(
    weaviateUrl, // Replace with your Weaviate Cloud URL
    weaviateApiKey, // Replace with your Weaviate Cloud key
    config -> config.setHeaders(
        Map.of("X-OpenAI-Api-Key", openaiApiKey)) // Replace with your OpenAI API key
);

CollectionHandle<Map<String, Object>> questions = client.collections.use("Question");

var response = questions.generate.nearText(
    "biology",
    // Query configuration (nearText and limit)
    q -> q.limit(2),
    // Generative configuration (the RAG task)
    g -> g.groupedTask(
        "Write a tweet with emojis about these facts.",
        c -> c.generativeProvider(GenerativeProvider.openai(o -> o))));

// Use `.generative()` to access the generated text
System.out.println(response.generative().text());

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

```csharp title="C#" {1-6}
var ragResponse = await questions.Generate.NearText(
    "biology",
    limit: 2,
    groupedTask: new GroupedTask("Write a tweet with emojis about these facts."),
    provider: new Providers.OpenAI() { }
);

// Inspect the results
Console.WriteLine(JsonSerializer.Serialize(ragResponse.Generative.Values));
```

```bash title="Curl"
# Best practice: store your credentials in environment variables
# export WEAVIATE_URL="YOUR_INSTANCE_URL"    # Your Weaviate instance URL
# export WEAVIATE_API_KEY="YOUR_API_KEY"     # Your Weaviate instance API key
# export OPENAI_API_KEY="YOUR_API_KEY"       # Your OpenAI API key

echo '{
  "query": "{
    Get {
      Question (
        limit: 2
        nearText: {
          concepts: [\"biology\"],
        }
      ) {
        question
        answer
        category
        _additional {
          generate(
            groupedResult: {
              task: \"\"\"
                Write a tweet with emojis about these facts.
              \"\"\"
            }
          ) {
            groupedResult
            error
          }
        }
      }
    }
  }"
}' | tr -d "\n" | curl \
    -X POST \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $WEAVIATE_API_KEY" \
    -H "X-OpenAI-Api-Key: $OPENAI_API_KEY" \
    -d @- \
    $WEAVIATE_URL/v1/graphql
```
:::

:::callout{intent="info" title="OpenAI API key in the header"}
Note that this code includes an additional header for the OpenAI API key. Weaviate uses this key to access the OpenAI generative AI model and perform retrieval augmented generation (RAG).
:::

Run this code to perform the query. Here is one possible response (your response will likely be different).

```text
🧬 In 1953 Watson & Crick built a model of the molecular structure of DNA, the gene-carrying substance! 🧬🔬

🦢 2000 news: the Gunnison sage grouse isn't just another northern sage grouse, but a new species! 🦢🌿 #ScienceFacts #DNA #SpeciesClassification
```

The response should be new, yet familiar. This is because you have seen the entries above for `DNA` and `species` in the [semantic search](#31-semantic-search) section.

The power of RAG comes from the ability to transform your own data. Weaviate helps you in this journey by making it easy to perform a combined search & generation in just a few lines of code.

## Recap

In this quickstart guide, you:

- Created a free cluster on Weaviate Cloud.
- Defined a collection and added data.
- Performed queries, including:
  - Semantic search, and
  - Retrieval augmented generation.

Where to go next is up to you. We include some suggested steps and resources below.

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