---
title: "Keep short-lived values"
description: "Store drafts and counters under a key with an expiry, scoped to the tenant, on a file in development and Redis in production."
section: "guides"
status: "Building for 0.3"
spec: "kv"
canonical: "https://mainsdk.dev/docs/guides/keep-short-lived-values"
updated: "2026-10-28"
---

# Keep short-lived values

> Store drafts and counters under a key with an expiry, scoped to the tenant, on a file in development and Redis in production.

Status: Building for 0.3 · Canonical: https://mainsdk.dev/docs/guides/keep-short-lived-values · Updated: 2026-10-28

You will keep a draft for a day and count events in a fixed window, using `kv` on a local file first and Redis when you deploy. It takes about 10 minutes and needs no account for the local part.

## You need

- A project with `main.yaml`.
- For production: a Redis URL as a secret, for example `REDIS_URL`.

## 1. Store and read a value

```yaml title="main.yaml"
kv:
  driver: local
  file: .mainsdk/kv.json     # optional: keeps values across restarts
```

```ts title="lib/draft.ts"
import { kv } from "mainsdk";

const userId = "u_1";   // the signed-in user

await kv.set(`draft:${userId}`, { step: 2 }, { ttl: "1d" });
const draft = await kv.get<{ step: number }>(`draft:${userId}`);   // null once it expires
```

You should see `get` return the value now and `null` after a day.

## 2. Count in a window

```ts title="lib/hits.ts"
import { kv } from "mainsdk";

const userId = "u_1";
const n = await kv.incr(`hits:${userId}`, { ttl: "1m" });   // 1, 2, 3 ... then a new window
```

The expiry is set when the key is created, so the window doesn't move. Use [`limits`](https://mainsdk.dev/docs/interfaces/limits) when you want a refusal with `Retry-After`.

## 3. Move to Redis

```yaml title="main.yaml"
kv:
  driver: redis
  redis: { url: secret:REDIS_URL, prefix: myapp }
```

Add the Redis host to `network.allow`, or let `mainsdk discover` list it. Your calls don't change. Values are not copied from the file.

## Ask your agent

```text
Goal: keep onboarding drafts for a day and count invites per hour.
Touch: main.yaml (kv section), the draft and invite code, one test with the fake clock.
Rules: pass a ttl on every draft and counter; never put personal data in a kv value; read the Redis URL from a secret.
Verify: pnpm mainsdk check && pnpm test
Never weaken or skip a check; fix the finding it names.
```

## Next

- [Key-value store](https://mainsdk.dev/docs/interfaces/kv)
- [Rate limits and quotas](https://mainsdk.dev/docs/interfaces/limits)
- [Network permissions](https://mainsdk.dev/docs/interfaces/network)
