# How to manage KV Store with Functions

import DocButton from '~/components/webkit/DocButton.vue';

This guide shows you how to interact with KV Store from your functions to 
store, retrieve, and delete key-value data.

<DocButton href="/en/documentation/products/store/kv-store/" label="Go to KV Store reference" kind="secondary" size="medium" />

---

## Requirements 

Before you begin, make sure you have:

- [Functions enabled](/en/documentation/products/build/applications/functions/) in your application.
- A KV Store namespace created via Console or API.

---

## Creating a function to interact with KV Store

Follow these steps to create a function that communicates with KV Store:

1. Access [Azion Console](https://console.azion.com).
2. On the upper-left corner, select **Functions**.
3. Click **+ Function**.
4. Enter a name for your function, for example: `kv-store-handler`.
5. Delete the placeholder code in the editor.
6. Paste one of the code examples below based on your use case.

---

## Storing data

This example demonstrates how to store different types of data in KV Store:

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

    // Store a simple string
    await kv.put("greeting", "Hello, World!");

    // Store a JSON object
    await kv.put("user-preferences", {
        theme: "dark",
        language: "en",
        notifications: true
    });

    // Store with metadata and expiration
    await kv.put("session-token", "abc123xyz", {
        metadata: { userId: "user-42" },
        expirationTtl: 3600 // expires in 1 hour
    });

    return new Response("Data stored successfully", {
        headers: { "Content-Type": "text/plain" },
        status: 200
    });
}

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

---

## Retrieving data

This example shows how to retrieve data in different formats:

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

    // Get as text (default)
    const greeting = await kv.get("greeting", "text");

    // Get as JSON object
    const preferences = await kv.get("user-preferences", "json");

    // Handle missing keys
    const missing = await kv.get("non-existent-key", "text");
    if (missing === null) {
        console.log("Key not found");
    }

    const response = {
        greeting,
        preferences,
        keyExists: missing !== null
    };

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

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

---

## Retrieving multiple keys

Fetch multiple values in a single operation:

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

    // Store some test data
    await kv.put("user-1", "Alice");
    await kv.put("user-2", "Bob");
    await kv.put("user-3", "Charlie");

    // Retrieve multiple keys at once
    const keys = ["user-1", "user-2", "user-3", "user-4"];
    const users = await kv.get(keys, "text");

    // Result: { "user-1": "Alice", "user-2": "Bob", "user-3": "Charlie", "user-4": null }

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

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

---

## Retrieving data with metadata

Use `getWithMetadata` to retrieve both the value and its associated metadata:

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

    // Store data with metadata
    await kv.put("session", "active-session-data", {
        metadata: { 
            createdAt: new Date().toISOString(),
            userId: "user-42"
        }
    });

    // Retrieve with metadata
    const result = await kv.getWithMetadata("session", "text");

    console.log(`Value: ${result.value}`);
    console.log(`Metadata: ${JSON.stringify(result.metadata)}`);

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

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

---

## Deleting data

Remove a key from the store:

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

    const key = "session-token";

    // Delete the key
    await kv.delete(key);

    return new Response(`Key '${key}' deleted`, {
        headers: { "Content-Type": "text/plain" },
        status: 200
    });
}

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

---

## Working with binary data

Store and retrieve binary data using ArrayBuffer:

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

    // Store binary data
    const encoder = new TextEncoder();
    const binaryData = encoder.encode("Binary content here").buffer;
    await kv.put("binary-key", binaryData);

    // Retrieve as ArrayBuffer
    const retrieved = await kv.get("binary-key", "arrayBuffer");

    // Decode back to string
    const decoder = new TextDecoder("utf-8");
    const decodedString = decoder.decode(retrieved);

    return new Response(decodedString, {
        headers: { "Content-Type": "text/plain" },
        status: 200
    });
}

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

---

## Working with streams

For large data, use ReadableStream for efficient memory usage:

```javascript
async function handleRequest(request) {
    const kv = new Azion.KV();
    const key = "large-content";

    // Retrieve as stream
    const stream = await kv.get(key, "stream");

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

    // Return the stream directly in the response
    return new Response(stream, {
        headers: { "Content-Type": "application/octet-stream" },
        status: 200
    });
}

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

---

## Using specific namespaces

Work with different namespaces for data isolation:

```javascript
async function handleRequest(request) {
    // Use a specific namespace
    const productionKV = new Azion.KV("production-data");
    const stagingKV = new Azion.KV("staging-data");

    // Or use the open method
    const cacheKV = await Azion.KV.open("cache-namespace");

    // Each namespace is isolated
    await productionKV.put("config", "production-value");
    await stagingKV.put("config", "staging-value");

    const prodConfig = await productionKV.get("config", "text");
    const stagingConfig = await stagingKV.get("config", "text");

    return new Response(JSON.stringify({
        production: prodConfig,
        staging: stagingConfig
    }), {
        headers: { "Content-Type": "application/json" },
        status: 200
    });
}

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

---

## Instantiating the function

After creating your function, you need to instantiate it in your application:

<DocButton href="/en/documentation/products/guides/build/instantiate-functions/" label="Go to how to instantiate functions in your application" kind="secondary" size="medium" />

---

## Next steps

- Learn more about [KV Store](/en/documentation/products/store/kv-store/)
- Explore [Functions](/en/documentation/products/build/edge-application/edge-functions/)