ViteHub

KV usage

Practical patterns for keys, JSON values, prefixes, deletes, lists, clears, and provider-neutral runtime code.

After the quickstart works, most KV code falls into four patterns: choose stable keys, store JSON values, group related keys with prefixes, and keep provider details out of route code.

Import the Runtime Handle

Use the canonical portable import from server/runtime code:

import { kv } from '@vitehub/kv'

The handle is backed by Nitro storage. Nitro mounts the active driver at startup, and Nuxt uses that Nitro path under the hood.

Set and Get JSON Values

kv.set() stores one value. kv.get() returns that value or null when the key is missing.

await kv.set('settings', {
  theme: 'system',
  notifications: true,
})

const settings = await kv.get<{
  theme: string
  notifications: boolean
}>('settings')

Route example:

server/api/settings.get.ts
import { kv } from '@vitehub/kv'

export default defineEventHandler(async () => {
  const settings = await kv.get('settings')

  return {
    settings: settings ?? {
      theme: 'system',
      notifications: true,
    },
  }
})

KV keys are strings. Use prefixes when a feature owns a group of values:

await kv.set('users:ava:preferences', { density: 'compact' })
await kv.set('users:ava:flags', { beta: true })

Then list only that group:

const userKeys = await kv.keys('users:ava')

Example response:

{
  "keys": [
    "users:ava:flags",
    "users:ava:preferences"
  ]
}

Check Before Doing Expensive Work

Use kv.has() when the value is not needed:

if (await kv.has('reports:daily:2026-04-26')) {
  return { cached: true }
}

Use kv.get() when the route needs the value anyway. That avoids a separate round trip for remote providers.

Delete One Key

await kv.del('settings')

Use this for explicit user actions such as resetting preferences or removing a cache entry.

Clear a Prefix

kv.clear() clears the whole active store. Pass a prefix when only one feature namespace should be removed:

await kv.clear('users:ava')
Use unscoped kv.clear() carefully. In hosted providers it targets the configured namespace or database, not only the current route.

Keep Provider Logic in Config

Route code should look the same for local, Cloudflare, and Vercel:

await kv.set('settings', { enabled: true })
return { settings: await kv.get('settings') }

Provider details belong in config:

kv: {
  driver: 'fs-lite',
  base: '.data/kv',
}

Pass Driver-Specific Options Intentionally

Every method accepts an optional options argument and passes it to the underlying unstorage driver:

await kv.set('settings', { enabled: true }, {
  ttl: 60,
})

Those options are driver-specific. ViteHub does not currently define a portable option contract for TTLs, metadata, or consistency behavior.

Disable KV

Set kv: false when a Nuxt or Nitro app should install the package but not mount runtime KV:

export default defineNuxtConfig({
  modules: ['@vitehub/kv/nuxt'],
  kv: false,
})

Next Steps

Copyright © 2026