> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# KV Use Cases

> Real-world patterns for Telnyx KV including session storage, response caching, and feature flags at the edge, with application-level expiry.

Patterns for using KV in your edge functions.

These examples build on the raw `kvGet`/`kvPut` helpers from the [Quick Start](/docs/edge-compute/kv/quick-start) and the `kvGetWithExpiry`/`kvPutWithExpiry` helpers from [Key expiration](/docs/edge-compute/kv/ttl-and-metadata) (KV has no native TTL, so expiry is enforced in your code).

## Session Storage with Expiry

Store user sessions at the edge with an application-level expiry:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    const SESSION_TTL = 86400; // 24 hours

    async function handler(request) {
        const sessionId = request.headers.get("X-Session-ID");

        // Read session (null if missing or expired)
        let session = await kvGetWithExpiry(`session/${sessionId}`);

        if (!session) {
            session = JSON.stringify({ created: Date.now(), views: 0 });
        } else {
            const data = JSON.parse(session);
            data.views++;
            session = JSON.stringify(data);
        }

        // Store with a 24h expiry
        await kvPutWithExpiry(`session/${sessionId}`, session, SESSION_TTL);

        return new Response(session);
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import json, time

    SESSION_TTL = 86400  # 24 hours

    # kv_get_with_expiry / kv_put_with_expiry: see Key expiration
    async def handler(request):
        session_id = request.headers.get("X-Session-ID")
        session = await kv_get_with_expiry(f"session/{session_id}")

        if not session:
            session = json.dumps({"created": int(time.time()), "views": 0})
        else:
            data = json.loads(session)
            data["views"] += 1
            session = json.dumps(data)

        await kv_put_with_expiry(f"session/{session_id}", session, SESSION_TTL)
        return {"body": session}
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    const sessionTTL = 86400 // 24 hours

    // kvGetWithExpiry / kvPutWithExpiry: see Key expiration
    func handler(w http.ResponseWriter, r *http.Request) {
        sessionID := r.Header.Get("X-Session-ID")

        session, _ := kvGetWithExpiry(fmt.Sprintf("session/%s", sessionID))

        var data map[string]interface{}
        if session == "" {
            data = map[string]interface{}{"created": time.Now().Unix(), "views": 0}
        } else {
            json.Unmarshal([]byte(session), &data)
            data["views"] = data["views"].(float64) + 1
        }
        updated, _ := json.Marshal(data)

        kvPutWithExpiry(fmt.Sprintf("session/%s", sessionID), string(updated), sessionTTL)

        w.Header().Set("Content-Type", "application/json")
        w.Write(updated)
    }
    ```
  </Tab>
</Tabs>

## API Response Caching with Expiry

Cache expensive API responses with an application-level expiry:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    const CACHE_TTL = 300; // 5 minutes

    async function handler(request) {
        const cacheKey = `cache/api${new URL(request.url).pathname}`;

        // Check cache
        const cached = await kvGetWithExpiry(cacheKey);
        if (cached) {
            return new Response(cached, {
                headers: { "X-Cache": "HIT" }
            });
        }

        // Fetch from origin
        const response = await fetch("https://api.example.com/data");
        const data = await response.text();

        // Cache with a 5-minute expiry
        await kvPutWithExpiry(cacheKey, data, CACHE_TTL);

        return new Response(data, {
            headers: { "X-Cache": "MISS" }
        });
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    CACHE_TTL = 300  # 5 minutes

    async def handler(request):
        from urllib.parse import urlparse
        cache_key = f"cache/api{urlparse(request.url).path}"

        cached = await kv_get_with_expiry(cache_key)
        if cached:
            return {"body": cached, "headers": {"X-Cache": "HIT"}}

        async with httpx.AsyncClient() as client:
            resp = await client.get("https://api.example.com/data")
            data = resp.text

        await kv_put_with_expiry(cache_key, data, CACHE_TTL)
        return {"body": data, "headers": {"X-Cache": "MISS"}}
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    const cacheTTL = 300 // 5 minutes

    func handler(w http.ResponseWriter, r *http.Request) {
        cacheKey := fmt.Sprintf("cache/api%s", r.URL.Path)

        cached, _ := kvGetWithExpiry(cacheKey)
        if cached != "" {
            w.Header().Set("X-Cache", "HIT")
            w.Write([]byte(cached))
            return
        }

        resp, _ := http.Get("https://api.example.com/data")
        defer resp.Body.Close()
        data, _ := io.ReadAll(resp.Body)

        kvPutWithExpiry(cacheKey, string(data), cacheTTL)

        w.Header().Set("X-Cache", "MISS")
        w.Write(data)
    }
    ```
  </Tab>
</Tabs>

## Feature Flags

Store and retrieve feature flags (no expiry needed):

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    async function handler(request) {
        const newUIEnabled = await kvGet("flag/new-ui");

        if (newUIEnabled === "true") {
            return serveNewUI(request);
        }

        return serveOldUI(request);
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    async def handler(request):
        enabled = await kv_get("flag/new-ui")

        if enabled == "true":
            return serve_new_ui(request)

        return serve_old_ui(request)
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    func handler(w http.ResponseWriter, r *http.Request) {
        enabled, _ := kvGet("flag/new-ui")

        if enabled == "true" {
            serveNewUI(w, r)
            return
        }

        serveOldUI(w, r)
    }
    ```
  </Tab>
</Tabs>
