@repo/feature-flags
Turn features on or off without deploying code. Gradually roll out to 5%, 25%, 50% of users. Run A/B tests. Instantly disable broken features. Evaluated at the edge with zero latency.
Quick Start
Add feature flags in 5 minutes:
pnpm add @repo/feature-flagsCheck flags in code, enable for specific users, run experiments. Skip to Quick Start →
Why @repo/feature-flags?
Deploying features is risky. You can't test in production until you deploy, but deploying means all users see the change. If something breaks, you need to redeploy to fix it. A/B testing requires complex infrastructure.
@repo/feature-flags solves this by decoupling code deployment from feature activation. Deploy code safely, enable for 1% of users, validate, then expand to 100%.
Production-ready with edge evaluation (zero latency), user targeting, percentage rollouts, A/B testing, and instant kill switches.
Use cases
- Gradual rollouts — Launch to 5% of users, then 25%, then 100%
- A/B testing — Test two pricing pages, measure which converts better
- Beta access — Give paying customers early access to new features
- Kill switches — Instantly disable broken features without redeploying
- User targeting — Premium features only for paid users, regional features
How it works
@repo/feature-flags provides server and client APIs for checking feature flags:
import { getFlag } from "@repo/feature-flags/server";
// Check if feature is enabled
const newCheckoutEnabled = await getFlag("new-checkout");
if (newCheckoutEnabled) {
return <NewCheckout />;
} else {
return <OldCheckout />;
}Flags are stored in Vercel Edge Config and evaluated at the edge with zero latency.
Key features
Zero-latency evaluation — Flags checked at the edge, no API calls, works offline
Percentage rollouts — Show to 10%, 25%, 50% of users, consistent per user
User targeting — Enable for specific users, segments, or organizations
A/B testing — Multiple variants with automatic exposure tracking
Instant updates — Change flags from dashboard, no deployment needed
Local overrides — Test in development with URL parameters or env vars
Quick Start
1. Install the package
pnpm add @repo/feature-flags @vercel/flags @vercel/edge-config2. Configure Edge Config connection
EDGE_CONFIG=https://edge-config.vercel.com/xxxxx3. Check a feature flag (server)
import { getFlag } from "@repo/feature-flags/server";
export default async function HomePage() {
const newDashboardEnabled = await getFlag("new-dashboard");
if (newDashboardEnabled) {
return <NewDashboard />;
}
return <OldDashboard />;
}4. Check a feature flag (client)
"use client";
import { useFlag } from "@repo/feature-flags/client";
export function FeatureGate() {
const betaChatEnabled = useFlag("beta-chat");
if (!betaChatEnabled) return null;
return <BetaChat />;
}That's it! Your app now supports feature flags with zero-latency edge evaluation.
Run an A/B test
Test multiple variants and track exposure:
const { variant, trackExposure } = await getExperiment("pricing-test");
await trackExposure(); // Track that user saw this variant
if (variant === "control") return <OriginalPricing />;
if (variant === "variant-b") return <NewPricing />;Distribution
This package is available as @oneapp/feature-flags for use outside the monorepo.
npm install @oneapp/feature-flagsBuild configuration: Uses tsdown with
createDistConfig('react', ...) for distribution builds.
Technical Details
For Developers: Technical implementation details
Feature flag management for gradual rollouts, A/B testing, and feature toggling. Supports multiple providers and local overrides.
Installation
pnpm add @repo/feature-flagsPrerequisite
Requires Vercel Edge Config for production deployments.
Overview
| Property | Value |
|---|---|
| Location | packages/feature-flags |
| Dependencies | @vercel/flags, @vercel/edge-config |
| Providers | Vercel Edge Config, Environment |
Export Paths
| Path | Description |
|---|---|
@repo/feature-flags | Main exports |
@repo/feature-flags/server | Server-side utilities |
@repo/feature-flags/client | Client-side utilities |
Basic Usage
Check Flag (Server)
import { getFlag } from "@repo/feature-flags/server";
// highlight-next-line
const isEnabled = await getFlag("new-feature");
if (isEnabled) {
// Show new feature
}Check Flag (Client)
"use client";
import { useFlag } from "@repo/feature-flags/client";
function MyComponent() {
// highlight-next-line
const isEnabled = useFlag("new-feature");
if (!isEnabled) return null;
return <NewFeature />;
}Flag Types
Boolean Flags
// highlight-next-line
const isEnabled = await getFlag<boolean>("feature-enabled");String Flags
// highlight-next-line
const variant = await getFlag<string>("button-color");
// "blue" | "green" | "red"Number Flags
const limit = await getFlag<number>("api-rate-limit");JSON Flags
interface FeatureConfig {
enabled: boolean;
maxItems: number;
allowedUsers: string[];
}
// highlight-next-line
const config = await getFlag<FeatureConfig>("advanced-config");User Targeting
Personalization
Target specific users or user segments for personalized feature rollouts.
import { getFlag } from "@repo/feature-flags/server";
// highlight-start
const isEnabled = await getFlag("premium-feature", {
userId: user.id,
email: user.email,
plan: user.plan
});
// highlight-end
// Flag rules can target specific users or segmentsPercentage Rollouts
// In flag configuration:
// highlight-start
// {
// "beta-feature": {
// "percentage": 25,
// "enabled": true
// }
// }
// highlight-end
// 25% of users will see the feature
const isEnabled = await getFlag("beta-feature", {
userId: user.id // Used for consistent bucketing
});A/B Testing
import { getExperiment } from "@repo/feature-flags";
// highlight-start
const { variant, trackExposure } = await getExperiment("pricing-test", {
userId: user.id,
});
// Track that user saw the variant
await trackExposure();
// highlight-end
if (variant === "control") {
return <OriginalPricing />;
} else if (variant === "variant-a") {
return <NewPricingA />;
} else {
return <NewPricingB />;
}React Provider
// app/layout.tsx
import { FlagsProvider } from "@repo/feature-flags/client";
export default async function RootLayout({ children }) {
// highlight-next-line
// Pre-fetch flags on server
const flags = await getAllFlags();
return (
<FlagsProvider value={flags}>
{children}
</FlagsProvider>
);
}useFlags Hook
"use client";
import { useFlags } from "@repo/feature-flags/client";
function FeatureGate() {
// highlight-next-line
const flags = useFlags();
return (
<div>
{flags["new-dashboard"] && <NewDashboard />}
{flags["beta-chat"] && <BetaChat />}
);
}Middleware
Edge Runtime
Flags are evaluated at the edge for zero-latency feature toggling.
// middleware.ts
import { withFeatureFlags } from "@repo/feature-flags/server";
// highlight-start
export const middleware = withFeatureFlags(async (request, flags) => {
if (flags["maintenance-mode"]) {
return NextResponse.redirect(new URL("/maintenance", request.url));
}
return NextResponse.next();
});
// highlight-endLocal Overrides
Development
// .env.local
FEATURE_FLAGS_OVERRIDE = { "new-feature": true, "beta-feature": false };URL Overrides
Development Only
URL overrides should only be enabled in development or for authorized users.
// Enable for testing via URL
// https://app.example.com?ff_new-feature=true
import { withUrlOverrides } from "@repo/feature-flags/client";
// highlight-next-line
const flags = withUrlOverrides(serverFlags);Flag Definitions
// flags.ts
import { defineFlags } from "@repo/feature-flags";
// highlight-start
export const flags = defineFlags({
"new-dashboard": {
description: "New dashboard redesign",
defaultValue: false,
type: "boolean"
},
"api-version": {
description: "API version to use",
defaultValue: "v1",
type: "string",
options: ["v1", "v2", "v3"]
}
});
// highlight-endEdge Config Integration
import { createEdgeConfigClient } from "@repo/feature-flags";
// highlight-start
const client = createEdgeConfigClient({
connectionString: process.env.EDGE_CONFIG
});
const flags = await client.getAll();
// highlight-endEnvironment Variables
Required for Production
EDGE_CONFIG connection string is required for production feature flags.
# Vercel Edge Config
EDGE_CONFIG="https://edge-config.vercel.com/..."
# Feature flag overrides (development)
FEATURE_FLAGS_OVERRIDE={"flag-name":true}Related Packages
- @repo/analytics - Track feature usage
- @repo/observability - Monitor flag performance