Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ Lightweight, environment-based feature flag system for Nuxt - made for developer
- 🎯 Roll out features to internal QA teams without branching or releases
- 📆 Schedule feature launches for specific environments or timeframes
- 🕵️‍♀️ Detect undeclared feature flags at build time with configurable validation and precise file context
- 🌳 Group flags with hierarchical names and enable bundles via wildcard (`*`) patterns

## Planned Features

- 📊 A/B testing support for feature flags
- 💡 Flag descriptions / metadata for better documentation, DevTools tooltips, or internal usage notes
- 🧩 Nuxt DevTools integration with a Feature Flag Explorer and Environment Switcher
- 🔄 Dynamic feature flag updates without server restarts through a remote config service
- 📊 A/B testing support for feature flags
- 📈 Analytics for feature flag usage
- 🧍‍♂️ Show features only for specific users (e.g., staff-only UIs, admin panels etc.)
- 🧬 Environment inheritance which lets environments inherit feature flags from others
- 💡 Flag descriptions / metadata for better documentation, DevTools tooltips, or internal usage notes
- 🛠 Programmatic overrides to toggle or override feature flags dynamically at runtime (e.g., per user or session)
- 📈 Analytics for feature flag usage and user feedback collection

## Quick Setup

Expand Down Expand Up @@ -53,6 +53,49 @@ export default defineNuxtConfig({
})
```

### Hierarchical & Wildcard Flags

Feature flags can be organized with `/`-separated paths and enabled in bulk using `*`.

```ts
export default defineNuxtConfig({
modules: ['nuxt-feature-flags-module'],
featureFlags: {
environment: process.env.FEATURE_ENV || 'development',
flagSets: {
development: [
'solutions/*',
'staging/*',
'internal/experimental/ui'
],
staging: [
'solutions/company-portal/addons/sales',
'solutions/company-portal/addons/marketing',
'internal/experimental/ui'
],
production: [
'solutions/company-portal/addons/sales'
]
}
}
})
```

```ts
const { isEnabled } = useFeatureFlag()

if (isEnabled('solutions/company-portal/addons/sales')) {
// sales addon enabled
}

if (isEnabled('solutions/*')) {
// any solution-related flag is active
}
```

> [!CAUTION]
> Using `*` enables every flag and the validator will emit a warning. Reserve it for debugging scenarios.

Use in your app:

```html
Expand Down
11 changes: 9 additions & 2 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ export default defineNuxtConfig({
activeFrom: '2000-01-01T00:00:00Z',
activeUntil: '2001-01-01T00:00:00Z',
},
'solutions/*',
'internal/experimental/ui',
],
staging: ['newSystem'],
production: [],
staging: [
'newSystem',
'solutions/company-portal/addons/sales',
'solutions/company-portal/addons/marketing',
'internal/experimental/ui',
],
production: ['solutions/company-portal/addons/sales'],
},
validation: {
mode: 'warn',
Expand Down
45 changes: 45 additions & 0 deletions playground/pages/hierarchical.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<div class="min-h-screen p-12 text-white bg-neutral-950">
<h2 class="text-2xl font-bold mb-4">
🌳 Hierarchical Flags Demo
</h2>
<p class="mb-4">
The <code class="text-emerald-400">solutions/*</code> wildcard enables all nested solution flags.
</p>
<ul class="space-y-2 list-disc pl-6">
<li
v-feature="'solutions/company-portal/addons/sales'"
class="text-emerald-400"
>
Sales addon is enabled
</li>
<li
v-feature="'solutions/company-portal/addons/marketing'"
class="text-emerald-400"
>
Marketing addon is enabled
</li>
<li
v-feature="'internal/experimental/ui'"
class="text-emerald-400"
>
Internal experimental UI is enabled
</li>
</ul>
<p
v-if="isEnabled('solutions/*')"
class="mt-6 text-emerald-400"
>
Group check for <code>solutions/*</code> returned true.
</p>
</div>
</template>

<script setup lang="ts">
const { isEnabled } = useFeatureFlag()

useSeoMeta({
title: 'Nuxt Feature Flags Playground - Hierarchical Flags',
description: 'Demonstrates hierarchical feature flags with wildcard bundling.',
})
</script>
20 changes: 20 additions & 0 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@
Redirects to <code>/404</code> unless <code>'newSystem'</code> is active.
</p>
</div>

<!-- Hierarchical Flags Demo -->
<div class="bg-white/10 backdrop-blur-lg rounded-2xl p-6 border border-white/10 shadow-lg">
<h2 class="text-lg font-semibold mb-2 text-emerald-300">
🌳 Hierarchical Flags
</h2>
<button
class="rounded-lg bg-neutral-800 hover:opacity-80 text-white py-2 px-4 transition ease-in-out duration-200 cursor-pointer"
@click="navigateToHierarchical"
>
View Demo
</button>
<p class="text-neutral-400 text-sm mt-2">
Demonstrates grouped flags enabled via wildcard patterns.
</p>
</div>
</div>

<!-- Non-existing feature flag use to trigger strict mode -->
Expand Down Expand Up @@ -129,6 +145,10 @@ function navigateToProtected() {
}
}

function navigateToHierarchical() {
navigateTo('/hierarchical')
}

useSeoMeta({
title: 'Nuxt Feature Flags Playground',
description: 'A playground for the Nuxt Feature Flags Module. Test and explore feature flags in a Nuxt application.',
Expand Down
9 changes: 9 additions & 0 deletions playground/server/api/solutions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { isFeatureEnabled } from '../../../src/runtime/server/isFeatureEnabled'

export default defineEventHandler((event) => {
if (!isFeatureEnabled('solutions/company-portal/addons/sales', event)) {
return sendError(event, createError({ statusCode: 403, message: 'Sales addon disabled' }))
}

return { message: 'Sales addon feature unlocked 🎉' }
})
Loading