Skip to content

Feature Toggles

v0.2.0State & DataVueNuxt

Lightweight, backend-agnostic feature flags plugin for Vue 3 — boolean and multivariate flags, contextual rules, live updates, and a DevTools overlay.

Feature Toggles
Get started →
npm install vue-feature-toggles@latest
01 — Purpose

When you'd reach for this

A new feature's code is often ready before marketing, QA, or the product manager are ready to turn it on — a feature flag separates the moment of deployment from the moment a feature actually becomes visible to users.

A new feature isn't turned on for everyone at once

First 5% of users see it, then 25%, then everyone — if something goes wrong, rolling back is easier than cleaning up after a full release.

Two versions of a feature need comparing, not just on or off

Some users see the old checkout button, others see the new one, and conversion is compared based on actual usage, not on which version the team happens to prefer.

QA needs to switch between test scenarios quickly

One set of features is on to check a new onboarding flow, another is on to test regression against old behavior. Instead of clicking through a dozen toggles by hand, a whole set is saved and switched on with one click.

A feature needs to be turned off right now, no redeploy

Something breaks overnight with a recently shipped feature, and nobody with server access is around — the flag can be flipped off remotely, and it takes effect immediately, without rebuilding or redeploying anything.

02 — Features

At a glance

Boolean and multivariate flags

Boolean and multivariate flags

Control features with simple boolean flags or string variants for A/B tests and phased rollouts. Static flags, async backend loading, periodic polling, and a priority chain (URL → runtime → rules → loader → static → defaultValue) give you full control over the logic.

Contextual rules, URL, and local storage

Contextual rules, URL, and local storage

Reactive rules based on any conditions (time, cookies, prefers-color-scheme) auto‑update flags. URL parameters let you override flags without a page reload, and persisted flags survive in localStorage. All work together, providing flexibility at every level.

Groups, dependencies, and profiles

Groups, dependencies, and profiles

Group flags for mass enable/disable. Set dependencies so one flag auto‑disables when another is off. Save named override sets as profiles for quick switching between scenarios (demo, QA).

Convenient API for components and logic

Convenient API for components and logic

Use the declarative <Feature> component with default/fallback/loading slots, the v-feature directive for v‑show‑style toggling, and the useFeature composable for reactive logic. Multivariate flags are supported via <FeatureVariant> and useFeatureVariant. All tools are type‑safe.

DevTools, CLI, and ready integrations

DevTools, CLI, and ready integrations

A built‑in floating DevTools panel for inspecting and controlling flags, a CLI for analyzing flags in code (list/check/stale), adapters for LaunchDarkly, Unleash, and Flagsmith. A Nuxt module with SSR hydration, a Storybook decorator, and a Vite plugin to strip DevTools in production.

Percentage rollout and date-based scheduling

Percentage rollout and date-based scheduling

Give a flag a { value, rollout } object and it turns on only for that percentage of users, deterministically bucketed by a hash of their id rather than randomly. Schedule flags to activate on specific future dates, and metadata plus an expiry date help track down stale toggles.

03 — Quick example

See how it works

A flag decided by context, not hardcoded

Rules are plain reactive functions — dark mode from the system preference, a chat widget from time of day, developer access from a cookie. Still overridable by a URL param or setFlag().

rules.ts
import { FeatureToggles } from 'vue-feature-toggles'

app.use(FeatureToggles, {
  rules: {
    darkMode: () => window.matchMedia('(prefers-color-scheme: dark)').matches,
    liveChatWidget: () => {
      const h = new Date().getHours()
      return h >= 9 && h < 18
    },
    devFeatures: () => document.cookie.includes('internal=1'),
  },
})

// Rules are reactive functions, re-evaluated whenever their inputs change —
// still overridable by a URL param or setFlag() at runtime.

An A/B test without a single v-if

checkoutFlow holds a string variant instead of a boolean — <FeatureVariant> renders the right slot on its own, and switching via ?feature:checkoutFlow=v2 works without a reload.

CheckoutSwitch.vue
<script setup lang="ts">
import { useFeatureVariant } from 'vue-feature-toggles'

const variant = useFeatureVariant('checkoutFlow') // Ref<string>
</script>

<template>
  <FeatureVariant name="checkoutFlow">
    <template #v1><CheckoutV1 /></template>
    <template #v2><CheckoutV2 /></template>
    <template #fallback><CheckoutLegacy /></template>
  </FeatureVariant>
</template>

<!-- URL overrides work identically: ?feature:checkoutFlow=v2 -->

Flags change on the fly — no reload, no polling

The server pushes { betaSearch: true } over SSE or WebSocket, and every component using that flag re-renders instantly — no polling required.

live-updates.ts
import { FeatureToggles } from 'vue-feature-toggles'

app.use(FeatureToggles, {
  loader: async () => fetch('/api/flags').then((r) => r.json()),
  liveUpdates: { type: 'sse', url: '/api/flags/stream' },
})

// The server pushes { "betaSearch": true }, and every component using that
// flag re-renders instantly — no polling, no page reload.