# Write key-value pairs

To create a new key-value pair, or to update the value for a particular key, 
call the `put()` method on your KV instance:

```javascript
await kv.put(key, value);
```

## Example

An example of writing a key-value pair from within a Function:

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

  try {
    await kv.put("first-key", "This is the value for the key");

    return new Response("Successful write", { status: 201 });
  } catch (e) {
    return new Response(e.message, { status: 500 });
  }
}

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

---

## Reference

### `put()` method

To create a new key-value pair, or to update the value for a particular key, 
call the `put()` method on your KV instance:

```javascript
await kv.put(key, value, options?);
```

#### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `key` | `string` | The key to associate with the value. Keys have a maximum length of 512 bytes. |
| `value` | `string` \| `object` \| `ArrayBuffer` \| `ReadableStream` | The value to store. The type is inferred. The maximum size of a value is 25 MB. |
| `options` | `object` | Optional. An object containing `expiration`, `expirationTtl`, and `metadata` attributes. |

#### Options

| Option | Type | Description |
|--------|------|-------------|
| `expiration` | `number` | The number representing when to expire the key-value pair in seconds since epoch. |
| `expirationTtl` | `number` | The number representing when to expire the key-value pair in seconds from now. The minimum value is 60. |
| `metadata` | `object` | An object that must serialize to JSON. The maximum size of the serialized JSON representation is 1024 bytes. |

#### Response

| Response | Type | Description |
|----------|------|-------------|
| `response` | `Promise<void>` | A Promise that resolves if the update is successful. |

The `put()` method returns a Promise that you should `await` to verify a 
successful update.

---

## Guidance

### Writing different value types

You can store different types of values:

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

  // Store a string value
  await kv.put("user-name", "John Doe");

  // Store a JSON object (automatically stringified)
  await kv.put("user-data", { id: 123, role: "admin" });

  // Store an ArrayBuffer
  const encoder = new TextEncoder();
  const buffer = encoder.encode("binary data").buffer;
  await kv.put("binary-key", buffer);

  // Store a ReadableStream (for large data)
  const stream = new ReadableStream({
    start(controller) {
      controller.enqueue(new TextEncoder().encode("large data..."));
      controller.close();
    }
  });
  await kv.put("stream-key", stream);

  return new Response("Data stored", { status: 201 });
}

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

### Concurrent writes to the same key

Due to the eventually consistent nature of KV Store, concurrent writes to the 
same key can end up overwriting one another. If concurrent writes are made to 
the same key, the last write will take precedence.

Writes are immediately visible to other requests in the same global network 
location, but can take up to 60 seconds (or the value of the `cacheTtl` 
parameter of the `get()` or `getWithMetadata()` methods) to be visible in 
other parts of the world.

### Expiring keys

KV Store offers the ability to create keys that automatically expire. You can 
configure expiration to occur either at a particular point in time (using the 
`expiration` option), or after a certain amount of time has passed since the 
key was last modified (using the `expirationTtl` option).

Once the expiration time of an expiring key is reached, it will be deleted 
from the system. After its deletion, attempts to read the key will behave as 
if the key does not exist.

:::note
Expiration targets that are less than 60 seconds into the future are not 
supported. This is true for both expiration methods.
:::

#### Create expiring keys

To create expiring keys, set `expiration` in the `put()` options to a number 
representing the seconds since epoch, or set `expirationTtl` in the `put()` 
options to a number representing the seconds from now:

```javascript
// Expire at a specific time (seconds since epoch)
await kv.put("session-key", "session-data", {
  expiration: Math.floor(Date.now() / 1000) + 3600 // 1 hour from now
});

// Expire after a duration (TTL in seconds)
await kv.put("cache-key", "cached-data", {
  expirationTtl: 300 // 5 minutes from now
});
```

### Metadata

To associate metadata with a key-value pair, set `metadata` in the `put()` 
options to an object (serializable to JSON):

```javascript
await kv.put("user-profile", JSON.stringify(userData), {
  metadata: { 
    createdBy: "admin",
    version: 1,
    tags: ["user", "profile"]
  }
});
```

You can later retrieve this metadata using the `getWithMetadata()` method.

### Rate limits

KV Store has a maximum of 1 write to the same key per second. Writes made to 
the same key within 1 second may cause rate limiting errors.

You should not write more than once per second to the same key. Consider 
consolidating your writes to a key within a Function invocation to a single 
write, or wait at least 1 second between writes.

### Storing large data with streams

For large payloads, use `ReadableStream` to stream data efficiently:

```javascript
async function handleRequest(request) {
  const kv = new Azion.KV();
  const dataSizeInKB = 500;
  const totalSize = dataSizeInKB * 1024;
  const chunkSize = 64 * 1024; // 64KB chunks

  const stream = new ReadableStream({
    async start(controller) {
      const encoder = new TextEncoder();
      const numChunks = Math.ceil(totalSize / chunkSize);

      for (let i = 0; i < numChunks; i++) {
        const currentChunkSize = Math.min(chunkSize, totalSize - i * chunkSize);
        const chunk = "a".repeat(currentChunkSize);
        controller.enqueue(encoder.encode(chunk));
      }
      controller.close();
    },
  });

  await kv.put("large-file", stream);

  return new Response("Large data stored", { status: 201 });
}

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

---

## Related

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