On this page
Documentation
Everything you need to integrate feature flags with Flaglayer.
Quick Start
Pick your framework and get feature flags running in under two minutes.
React
1. Install
npm install @flaglayer/react
2. Wrap your app
import { FlagProvider } from '@flaglayer/react';function App() {return (<FlagProviderapiKey="fl_dev_..."context={{ userId: 'user-123' }}><MyComponent /></FlagProvider>);}
3. Use a flag
import { useBooleanFlag } from '@flaglayer/react';function MyComponent() {const { value: showDashboard, loading } = useBooleanFlag('new-dashboard', false);if (loading) return <Spinner />;return showDashboard ? <NewDashboard /> : <OldDashboard />;}
Next.js
1. Install
npm install @flaglayer/nextjs
2. Client components
Same API as @flaglayer/react — import from @flaglayer/nextjs instead.
import { FlagProvider, useBooleanFlag } from '@flaglayer/nextjs';
3. Server components
import { createFlagLayerServer } from '@flaglayer/nextjs/server';const fl = createFlagLayerServer({apiKey: process.env.FLAGLAYER_API_KEY!,});export default async function Page() {const result = await fl.evaluate('new-dashboard', { userId: 'user-123' });return result.value ? <NewDashboard /> : <OldDashboard />;}
Node.js
1. Install
npm install @flaglayer/node
2. Evaluate flags
import { FlagLayer } from '@flaglayer/node';const fl = new FlagLayer({apiKey: process.env.FLAGLAYER_API_KEY!,});const result = await fl.evaluate('new-dashboard', { userId: 'user-123' });console.log(result.value); // trueconsole.log(result.reason); // 'TARGETING_MATCH'
Concepts
Environments
Each project has separate environments (e.g. development, staging, production). Flags can have different rules per environment, and each environment has its own API keys. This lets you test flag changes in staging before rolling them out to production.
Flags & Rules
A flag is a named toggle that returns a typed value (boolean, string, or number). Each flag can have targeting rules per environment that control who sees which value. Rules include an enabled/disabled toggle, a rollout percentage, and optional user targeting.
Targeting
Targeting lets you control exactly who sees a flag. You can target by:
- Rollout percentage — gradually roll out to a percentage of users using consistent hashing (same user always gets the same result)
- User allowlist — enable for specific user IDs
- Email allowlist — enable for specific emails, with wildcard support (e.g.
*@company.com)
API Keys
API keys are scoped to an environment. Use them in your SDK client or API requests to authenticate. Keys are hashed on the server — you can only see the full key once when you create it. You can revoke and create new keys at any time.
SDK Reference
@flaglayer/sdk
The core JavaScript/TypeScript client. Works in any JS environment. Maintains a local cache of flags after calling identify().
npm install @flaglayer/sdk
Constructor
import { FlagLayer } from '@flaglayer/sdk';const fl = new FlagLayer({apiKey: 'fl_dev_...', // RequiredbaseUrl: 'https://...', // Optional, defaults to https://api.flaglayer.comprefix: 'exp_', // Optional, only fetch flags matching this prefix});
Methods
identify(context) — Set the user context and fetch all flags into the local cache.
await fl.identify({ userId: 'user-123', email: 'user@example.com' });
evaluate(flagKey, context) — Evaluate a single flag via API call. Returns a FlagResult.
const result = await fl.evaluate('new-feature', { userId: 'user-123' });// result = { value: true, reason: 'TARGETING_MATCH' }
getValue(flagKey) — Get the raw value of a cached flag.
const val = fl.getValue('theme'); // boolean | string | number | undefined
getBooleanValue(flagKey, defaultValue?) — Get a boolean flag from cache with optional default.
const enabled = fl.getBooleanValue('new-feature', false);
getStringValue(flagKey, defaultValue?) / getNumberValue(flagKey, defaultValue?) — Typed getters for string and number flags.
const plan = fl.getStringValue('plan-tier', 'free');const limit = fl.getNumberValue('rate-limit', 100);
getFlags() — Get all cached flags as a Record<string, FlagResult>.
const flags = fl.getFlags();// { 'new-feature': { value: true, reason: 'TARGETING_MATCH' }, ... }
refresh() — Re-fetch flags with the current context.
await fl.refresh();
@flaglayer/react
React hooks and provider for feature flags. Handles flag fetching, caching, and re-rendering automatically.
npm install @flaglayer/react
FlagProvider
Wrap your app with the provider. It initializes the SDK client and provides flag state to all child hooks.
import { FlagProvider } from '@flaglayer/react';function App() {return (<FlagProviderapiKey="fl_dev_..." // Requiredcontext={{ userId: 'user-123' }} // Required — EvaluationContextbaseUrl="https://..." // Optional, custom API URLprefix="exp_" // Optional, filter flags by prefixfallback={{ 'feature': { value: false, reason: 'DEFAULT' } }} // OptionalrefetchOnWindowFocus={true} // Optional, default: falserefetchInterval={30000} // Optional, ms — 0 to disable><MyComponent /></FlagProvider>);}
Hooks
useBooleanFlag(flagKey, defaultValue?) — Boolean flag with loading state. Recommended for on/off toggles.
import { useBooleanFlag } from '@flaglayer/react';const { value, loading } = useBooleanFlag('dark-mode', false);
useStringFlag(flagKey, defaultValue?) — String flag with loading state. Useful for A/B test variants, themes, etc.
import { useStringFlag } from '@flaglayer/react';const { value: variant, loading } = useStringFlag('checkout-variant', 'control');
useNumberFlag(flagKey, defaultValue?) — Number flag with loading state. Good for rate limits, thresholds, etc.
import { useNumberFlag } from '@flaglayer/react';const { value: maxItems, loading } = useNumberFlag('max-cart-items', 10);
useFlagValue(flagKey) — Any typed flag value. Returns boolean | string | number | undefined.
import { useFlagValue } from '@flaglayer/react';const { value, loading } = useFlagValue('my-flag');
useFlags() — All flags at once.
import { useFlags } from '@flaglayer/react';const { flags, loading } = useFlags();// flags: Record<string, FlagResult>
useFlagLayer() — Access the underlying FlagLayer client for manual operations.
import { useFlagLayer } from '@flaglayer/react';const client = useFlagLayer();await client.refresh();
useFlaglayerContext() — Full context with flags, loading, error, client, and refetch function.
import { useFlaglayerContext } from '@flaglayer/react';const { flags, loading, error, client, refetch } = useFlaglayerContext();
@flaglayer/nextjs
Next.js integration with server-side evaluation, client provider, and routing middleware.
npm install @flaglayer/nextjs
Client Components
Re-exports FlagProvider, useBooleanFlag, useStringFlag, useNumberFlag, useFlagValue, useFlags, and useFlagLayer from @flaglayer/react. Same API — just import from @flaglayer/nextjs.
Server Components
Stateless server-side evaluation. Each call hits the API directly — no local cache.
import { createFlagLayerServer } from '@flaglayer/nextjs/server';const fl = createFlagLayerServer({apiKey: process.env.FLAGLAYER_API_KEY!,});// Evaluate a single flagconst result = await fl.evaluate('new-feature', { userId: 'user-123' });// result = { value: true, reason: 'TARGETING_MATCH' }// Evaluate all flagsconst flags = await fl.evaluateAll({ userId: 'user-123' });// With prefix filterconst expFlags = await fl.evaluateAll({ userId: 'user-123' },{ prefix: 'exp_' });
Server Value Extractors
Helper methods to extract typed values from FlagResult objects.
const result = await fl.evaluate('plan-tier', { userId: 'user-123' });const enabled = fl.getBooleanValue(result, false);const plan = fl.getStringValue(result, 'free');const limit = fl.getNumberValue(result, 100);
Routing Middleware
Flag-based routing at the edge. Rewrite or redirect based on flag values — no client-side flicker.
// middleware.tsimport { createFlagLayerMiddleware } from '@flaglayer/nextjs/middleware';export default createFlagLayerMiddleware({apiKey: process.env.FLAGLAYER_API_KEY!,rules: [{ flag: 'new-pricing', match: '/pricing', rewrite: '/pricing-v2' },{ flag: 'maintenance', match: '/app/*', redirect: '/maintenance' },],getContext: (req) => ({userId: req.cookies.get('uid')?.value ?? 'anon',}),});
@flaglayer/node
Server-side Node.js client. Stateless — each call hits the API. Ideal for backend services, Express handlers, and serverless functions.
npm install @flaglayer/node
import { FlagLayer } from '@flaglayer/node';const fl = new FlagLayer({apiKey: process.env.FLAGLAYER_API_KEY!,baseUrl: 'https://...', // Optional, defaults to https://api.flaglayer.com});// Evaluate a single flag — returns FlagResultconst result = await fl.evaluate('new-feature', { userId: 'user-123' });console.log(result.value); // trueconsole.log(result.reason); // 'TARGETING_MATCH'// Evaluate all flags (with optional prefix filter)const flags = await fl.evaluateAll({ userId: 'user-123' },{ prefix: 'exp_' });// Extract typed values from resultsconst enabled = fl.getBooleanValue(result, false);const plan = fl.getStringValue(result, 'free');const limit = fl.getNumberValue(result, 100);
Testing
The React provider supports mock props for deterministic testing — no API calls needed.
import { FlagProvider } from '@flaglayer/react';// Mock specific flag values<FlagProviderapiKey="test"context={{ userId: 'test-user' }}mockFlags={{'new-dashboard': { value: true, reason: 'TARGETING_MATCH' },'dark-mode': { value: false, reason: 'DEFAULT' },}}><ComponentUnderTest /></FlagProvider>// Simulate loading state<FlagProviderapiKey="test"context={{ userId: 'test-user' }}mockLoading={true}><ComponentUnderTest /></FlagProvider>// Simulate error state<FlagProviderapiKey="test"context={{ userId: 'test-user' }}mockError={new Error('Network error')}><ComponentUnderTest /></FlagProvider>
Types
Key TypeScript types exported by the SDK packages.
FlagResult
All evaluation methods return a FlagResult — not a plain boolean.
interface FlagResult {value: boolean | string | number;reason: string; // 'TARGETING_MATCH' | 'DEFAULT' | 'DISABLED' | ...}
EvaluationContext
Passed to identify(), evaluate(), and the provider's context prop.
interface EvaluationContext {userId: string; // Required[key: string]: string | number | boolean | string[] | undefined; // Custom attributes}
EvaluationReason
type EvaluationReason =| 'TARGETING_MATCH' // Matched a targeting rule| 'DEFAULT' // Returned the default value| 'DISABLED' // Flag is disabled| 'PREREQUISITE_FAILED' // A prerequisite flag check failed| 'SCHEDULE_INACTIVE' // Outside the flag's active schedule| 'ARCHIVED' // Flag has been archived| 'ERROR'; // Evaluation error
FlagLayerError
Thrown by SDK methods on API errors.
import { FlagLayerError } from '@flaglayer/sdk';try {await fl.evaluate('flag', ctx);} catch (e) {if (e instanceof FlagLayerError) {console.log(e.code); // Error code stringconsole.log(e.status); // HTTP status number}}
API Reference
All SDK endpoints require an API key in the x-api-key header.
Evaluation
POST /v1/evaluate
Evaluate a single flag.
// Request{"flagKey": "new-feature","context": { "userId": "user-123", "email": "user@example.com" }}// Response{ "value": true, "reason": "TARGETING_MATCH" }
POST /v1/evaluate-all
Evaluate all flags for a user.
// Request{"context": { "userId": "user-123" },"prefix": "exp_"}// Response{"flags": {"exp_new-dashboard": { "value": true, "reason": "TARGETING_MATCH" },"exp_dark-mode": { "value": false, "reason": "DEFAULT" }}}
Admin
Admin endpoints use session authentication (used by the dashboard). These are available for building custom integrations.
| Resource | Endpoints |
|---|---|
| Projects | GET POST PATCH DELETE /v1/admin/projects |
| Flags | GET POST PATCH DELETE /v1/admin/flags |
| Flag Rules | GET PATCH /v1/admin/flags/:flagId/rules/:envId |
| Environments | GET POST /v1/admin/environments |
| API Keys | GET POST DELETE /v1/admin/api-keys |
| Users | GET /v1/admin/users · PATCH /:id/role · DELETE /:id |
| Invitations | POST /v1/admin/invitations · POST /:id/resend |
Error Responses
{ "statusCode": 401, "message": "Invalid API key" }{ "statusCode": 429, "message": "Rate limit exceeded" }{ "statusCode": 404, "message": "Flag not found" }
Evaluation endpoints are rate-limited per API key. Include your API key in the x-api-key header with every request.