# Read key-value pairs

To get the value for a given key, call the `get()` method on your KV instance:

```javascript
// Read individual key
const value = await kv.get(key);

// Read multiple keys
const values = await kv.get(keys);
```

The `get()` method returns a promise you can `await` to get the value.

If you request a single key as a string, you will get a single response in the 
promise. If the key is not found, the promise will resolve with the literal 
value `null`.

You can also request an array of keys. The return value will be an object with 
key-value pairs, where keys not found have `null` values.

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();

  try {
    // Read single key, returns value or null
    const value = await kv.get("first-key", "text");

    // Read multiple keys, returns object with values
    const values = await kv.get(["first-key", "second-key"], "text");

    // Read single key with metadata
    const valueWithMetadata = await kv.getWithMetadata("first-key", "text");

    // Read multiple keys with metadata
    const valuesWithMetadata = await kv.getWithMetadata(["first-key", "second-key"], "text");

    return new Response(JSON.stringify({
      value: value,
      values: values,
      valueWithMetadata: valueWithMetadata,
      valuesWithMetadata: valuesWithMetadata
    }), {
      headers: { "Content-Type": "application/json" }
    });
  } catch (e) {
    return new Response(e.message, { status: 500 });
  }
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
```

:::note
`get()` and `getWithMetadata()` methods may return stale values. If a given 
key has recently been read in a given location, writes or updates to the key 
made in other locations may take up to 60 seconds (or the duration of the 
`cacheTtl`) to display.
:::

---

## Reference

The following methods are provided to read from KV Store:

- [get()](#get-method)
- [getWithMetadata()](#getwithmetadata-method)

### `get()` method

Use the `get()` method to get a single value, or multiple values if given 
multiple keys.

#### Request a single key

To get the value for a single key, call the `get()` method on your KV instance:

```javascript
await kv.get(key, type?, options?);
```

##### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `key` | `string` | The key of the KV pair. |
| `type` | `"text"` \| `"json"` \| `"arrayBuffer"` \| `"stream"` | Optional. The type of the value to be returned. `text` is the default. |
| `options` | `{ cacheTtl?: number }` | Optional. Object containing the `cacheTtl` property. |

##### Options

| Option | Type | Description |
|--------|------|-------------|
| `cacheTtl` | `number` | Time in seconds to cache the result locally. Minimum value is 60. |

##### Response

| Response | Type | Description |
|----------|------|-------------|
| `response` | `Promise<string \| object \| ArrayBuffer \| ReadableStream \| null>` | The value for the requested KV pair, or `null` if not found. |

The response type depends on the `type` parameter:

| Type | Returns |
|------|---------|
| `"text"` | A `string` (default) |
| `"json"` | An object decoded from a JSON string |
| `"arrayBuffer"` | An `ArrayBuffer` instance |
| `"stream"` | A `ReadableStream` |

#### Request multiple keys

To get the values for multiple keys, call the `get()` method with an array:

```javascript
await kv.get(keys, type?);
```

##### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `keys` | `string[]` | The keys of the KV pairs. |
| `type` | `"text"` \| `"json"` | Optional. The type of the value to be returned. `text` is the default. |

##### Response

| Response | Type | Description |
|----------|------|-------------|
| `response` | `Promise<object>` | An object with key-value pairs. Keys not found have `null` values. |

---

### `getWithMetadata()` method

Use the `getWithMetadata()` method to get a single value along with its 
metadata, or multiple values with their metadata.

#### Request a single key with metadata

To get the value for a given key along with its metadata:

```javascript
await kv.getWithMetadata(key, type?, options?);
```

Metadata is a serializable value you append to each KV entry when using `put()`.

##### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `key` | `string` | The key of the KV pair. |
| `type` | `"text"` \| `"json"` \| `"arrayBuffer"` \| `"stream"` | Optional. The type of the value to be returned. `text` is the default. |
| `options` | `{ cacheTtl?: number }` | Optional. Object containing the `cacheTtl` property. |

##### Response

| Response | Type | Description |
|----------|------|-------------|
| `response` | `Promise<{ value: string \| object \| ArrayBuffer \| ReadableStream \| null, metadata: object \| null }>` | An object containing the value and metadata. |

If there is no metadata associated with the requested key-value pair, `null` 
will be returned for metadata.

#### Request multiple keys with metadata

To get the values for multiple keys along with their metadata:

```javascript
await kv.getWithMetadata(keys, type?);
```

##### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `keys` | `string[]` | The keys of the KV pairs. |
| `type` | `"text"` \| `"json"` | Optional. The type of the value to be returned. `text` is the default. |

##### Response

| Response | Type | Description |
|----------|------|-------------|
| `response` | `Promise<object>` | An object with keys mapped to `{ value, metadata }` objects. |

---

## Guidance

### Type parameter

For simple values, use the default `text` type which provides your value as a 
`string`. For convenience, a `json` type is also specified which will convert 
a JSON value into an object before returning it. For large values, use `stream` 
to request a `ReadableStream`. For binary values, use `arrayBuffer` to request 
an `ArrayBuffer`.

For large values, the choice of `type` can have a noticeable effect on latency 
and CPU usage. For reference, the `type` can be ordered from fastest to slowest 
as `stream`, `arrayBuffer`, `text`, and `json`.

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();

  // Get as text (default)
  const textValue = await kv.get("my-key", "text");

  // Get as JSON (automatically parsed)
  const jsonValue = await kv.get("my-key", "json");
  console.log(jsonValue.someProperty);

  // Get as ArrayBuffer
  const bufferValue = await kv.get("my-key", "arrayBuffer");
  const decoder = new TextDecoder("utf-8");
  const decodedString = decoder.decode(bufferValue);

  // Get as ReadableStream
  const streamValue = await kv.get("my-key", "stream");

  return new Response(textValue);
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
```

### CacheTtl parameter

`cacheTtl` is a parameter that defines the length of time in seconds that a KV 
result is cached in the global network location where it is accessed.

Defining the length of time in seconds is useful for reducing cold read latency 
on keys that are read relatively infrequently. `cacheTtl` is useful if your 
data is write-once or write-rarely.

:::note[Hot and cold reads]
A hot read means that the data is cached locally. A cold read means that the 
data is not cached, so it must be fetched from the central stores. Both 
existing key-value pairs and non-existent key-value pairs (negative lookups) 
are cached.
:::

`cacheTtl` is not recommended if your data is updated often and you need to 
see updates shortly after they are written, because writes from other global 
network locations will not be visible until the cached value expires.

The minimum value for `cacheTtl` is 60 seconds.

```javascript
// Cache the result for 5 minutes
const value = await kv.get("config-key", "json", { cacheTtl: 300 });
```

### Handling non-existent keys

When a key doesn't exist, `get()` returns `null`:

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();

  const value = await kv.get("non-existent-key", "text");

  if (value === null) {
    return new Response("Key not found", { status: 404 });
  }

  return new Response(value);
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
```

### Reading streams

For large values stored as streams, process the data incrementally:

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();

  const stream = await kv.get("large-file", "stream");

  if (stream instanceof ReadableStream) {
    const decoder = new TextDecoder();
    let text = "";

    for await (const chunk of stream) {
      text += decoder.decode(chunk, { stream: true });
    }
    text += decoder.decode();

    console.log(`Retrieved ${text.length} characters`);
  }

  // Or return the stream directly in a response
  return new Response(stream);
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
```

### Working with metadata

Retrieve both value and metadata in a single call:

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();

  const result = await kv.getWithMetadata("user-profile", "json");

  console.log("Value:", result.value);
  console.log("Metadata:", result.metadata);

  if (result.metadata && result.metadata.version) {
    console.log("Version:", result.metadata.version);
  }

  return new Response(JSON.stringify(result), {
    headers: { "Content-Type": "application/json" }
  });
}

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
```

---

## Related

- [Write key-value pairs](/en/documentation/runtime/api-reference/kv-store/write/)
- [Delete key-value pairs](/en/documentation/runtime/api-reference/kv-store/delete/)
- [KV Store API overview](/en/documentation/runtime/api-reference/kv-store/)