# Deno KV

Deno KV is a key-value store built into the runtime. Locally you open it with `Deno.openKv()`; on the new Deno Deploy it is available as a linkable database engine. As of 2026-08-03, Deno still marks KV as in development and subject to change, and local runs require `--unstable-kv`.

```ts
const kv = await Deno.openKv();

await kv.set(["sessions", sid], { userId, createdAt: new Date() });
const entry = await kv.get(["sessions", sid]);

const result = await kv.atomic()
  .check(entry) // commits only if the versionstamp is unchanged
  .set(["sessions", sid], { userId, rotatedAt: new Date() })
  .commit();
```

Local development: `Deno.openKv("./data/app.kv")` persists to a file; `Deno.openKv(":memory:")` is for tests.

```bash
# KV's underlying disk access needs no --allow-read/--allow-write (the official
# permissions docs say so explicitly); grant only what your app's own I/O requires
deno run --unstable-kv main.ts
```

<Callout type="warn" title="Platform status (verified 2026-08-03)">
Deploy Classic shut down on 2026-07-20. The new Deno Deploy supports Deno KV as a database engine linked to an app, and `Deno.openKv()` automatically connects to the isolated logical database for the current timeline. But the official migration guide states: Classic KV data is not migrated automatically—contact support@deno.com for assistance; KV Queues (`kv.enqueue()` / `kv.listenQueue()`) are not supported on the new platform; and an app can currently link only one database instance, so it cannot have both KV and PostgreSQL. Redesign before migrating if you depend on any of these.
</Callout>

## API essentials

- Keys are arrays: `["users", userId]`. Parts may be string, number, boolean, bigint, or Uint8Array, ordered lexicographically with type order taking precedence over value order.
- Values must be structured-clone compatible (objects, arrays, Map, Set, Date, Uint8Array, etc.); class instances, functions, and Symbols are not supported.
- `get` / `getMany` / `list` for reads. `list` scans by prefix or range in batches (default 500) and does not guarantee a single snapshot across batches.
- `set` / `delete`, plus `sum` / `min` / `max` (only inside atomic operations, only on `Deno.KvU64`).
- `atomic()` provides optimistic concurrency control: `.check()` asserts versionstamps, and on a failed `.commit()` you re-read and retry. There are no lock-based interactive transactions.
- `watch(keys)` returns a `ReadableStream` that pushes changes; rapid successive writes may be coalesced, so you are not guaranteed every intermediate state.

## Consistency model

- Writes are always strongly consistent.
- Reads can be strong (guaranteed to return the most recently written value) or eventual (faster, may return a stale value); `get` is a snapshot read in all consistency modes.
- Every write receives a monotonically increasing, non-sequential 12-byte versionstamp; all writes in one transaction share it.

Key limits from the official transactions documentation: max key size 2 KiB, max value size 64 KiB; `getMany` reads at most 10 keys; `list` batches at most 1000; a single atomic operation allows at most 100 checks, 1000 mutations, and 800 KiB total; `watch` accepts at most 10 keys.

## KV on the new Deno Deploy

- KV is provisioned through the organization's databases feature and assigned to an app; production, branch, and preview timelines automatically get isolated logical databases.
- Connecting from outside Deploy (for example, from a local CLI against the hosted database): use the connect URL `https://api.deno.com/v2/databases/<Database ID>/connect` with a personal or organization access token in the `DENO_KV_ACCESS_TOKEN` environment variable.
- Data residency: per the official docs, KV's primary region is Northern Virginia in the US, with read replicas in Europe and Asia. Writes are stored in and transit through the US, so workloads requiring strict EU residency are not suitable—the docs recommend their Postgres offerings instead.
- Current limitations: one database instance per app; the preview database is shared across all preview deployments; the database explorer does not support KV yet.

## When KV is the wrong choice

- You need queues: `enqueue` / `listenQueue` are unavailable on the new platform—use an external queue or a database-backed job table.
- You need relational queries, joins, or ad-hoc SQL analysis: KV offers key lookups and prefix scans only, and secondary indexes are your own maintenance burden.
- Individual values exceed 64 KiB, or a transaction would exceed the documented atomic limits.
- Strict EU data-residency compliance.
- One app needs both KV and PostgreSQL (current platform limitation).
- You need a frozen API: Deno still flags KV as subject to change.

Official references: [Deno KV overview](https://docs.deno.com/deploy/kv/), [KV operations and consistency](https://docs.deno.com/deploy/kv/operations/), [KV transactions and limits](https://docs.deno.com/deploy/kv/transactions/), [Key space and value types](https://docs.deno.com/deploy/kv/key_space/), [Deno KV on the new Deploy](https://docs.deno.com/deploy/reference/deno_kv/), [Classic migration guide](https://docs.deno.com/deploy/migration_guide/).
