Edge-first Unleash feature flags for Nuxt. Fetches pre-evaluated flags from the Unleash Proxy Frontend API, caches them with stale-while-revalidate, and hydrates to the client with zero flicker. No unleash-client SDK — works on Cloudflare Workers, Vercel, and Node.js.
- Edge-first — no Node.js-only dependencies, runs on Cloudflare Workers, Vercel, any runtime
- Zero flicker — flags evaluated server-side during SSR, hydrated to client
- Stale-while-revalidate — instant responses from cache, background refresh when stale
- Pluggable storage — NuxtHub KV, Nitro/unstorage drivers, or in-memory
- Auto-refresh — client polls for updates via internal API route, pauses when tab is hidden
- Zero dependencies — just
@nuxt/kitanddefu - Type safe — generated types for composables, server utils, and
$fetch
npx nuxt module add @adamkasper/nuxt-unleashConfigure in nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@adamkasper/nuxt-unleash'],
unleash: {
url: 'https://your-unleash-proxy.example.com/api/frontend',
token: 'your-frontend-api-token',
appName: 'my-app',
},
})All composables and server utils are auto-imported.
<script setup>
const showBanner = useFlag('new-banner')
</script>
<template>
<div v-if="showBanner">
Welcome to the new experience!
</div>
</template><script setup>
const variant = useVariant('checkout-experiment')
</script>
<template>
<CheckoutA v-if="variant.name === 'treatment-a'" />
<CheckoutB v-else-if="variant.name === 'treatment-b'" />
<CheckoutDefault v-else />
</template><script setup>
const { ready, flagCount } = useFlagsStatus()
</script>
<template>
<div v-if="!ready">
Loading flags...
</div>
<div v-else>
{{ flagCount }} flags loaded
</div>
</template>const allFlags = useAllFlags()
console.log(allFlags.value)
// { 'my-flag': { name, enabled, variant }, ... }// server/api/my-route.ts
export default defineEventHandler(async () => {
const { toggles } = await useUnleashFlags()
if (toggles['premium-api']?.enabled) {
return { tier: 'premium' }
}
return { tier: 'free' }
})| Option | Type | Default | Description |
|---|---|---|---|
url |
string |
required | Unleash Proxy Frontend API URL |
token |
string |
required | Frontend API token (server-only, never exposed to client) |
appName |
string |
required | Application name sent to the proxy |
environment |
string |
'default' |
Environment name |
refreshInterval |
number |
15000 |
Stale-while-revalidate TTL in ms |
clientRefreshInterval |
number |
30000 |
Client polling interval in ms (0 to disable) |
storage |
'nuxthub' | 'nitro' | 'memory' |
'memory' |
Storage backend for caching flags |
storageKey |
string |
'unleash:flags' |
Key prefix used in storage |
All options support NUXT_UNLEASH_* environment variable overrides:
NUXT_UNLEASH_TOKEN=prod:production.secret-token node .output/server/index.mjsServer startup
└─ Nitro plugin fetches flags from Unleash Proxy, stores in cache
SSR request
└─ Server plugin reads flags from cache (stale-while-revalidate)
└─ If stale, triggers background refresh
└─ Stores flags in useState() → hydrates to client
Client
└─ Reads hydrated flags immediately (zero flicker)
└─ Polls GET /api/_unleash/flags for updates (pauses when tab hidden)
| Composable | Returns | Description |
|---|---|---|
useFlag(name) |
ComputedRef<boolean> |
Whether a flag is enabled |
useVariant(name) |
ComputedRef<Variant> |
Variant details for A/B testing |
useFlagsStatus() |
{ ready, flagCount } |
Flag loading status |
useAllFlags() |
ComputedRef<Record<string, EvaluatedFlag>> |
All evaluated flags |
Auto-imported in the server/ directory:
| Utility | Returns | Description |
|---|---|---|
useUnleashFlags() |
Promise<CachedFlags> |
Read flags with stale-while-revalidate |
refreshUnleashFlags(opts?) |
Promise<CachedFlags | null> |
Force refresh from proxy |
Full documentation: nuxt-unleash.adamkasper.cz
pnpm install
pnpm dev:prepare
pnpm dev # Start playground
pnpm test # Run tests
pnpm lint # Lint