@flaggable/client
v0.1.8
Published
Type-safe, reactive feature flag SDK for JavaScript, TypeScript, React, and Next.js applications.
Readme
@flaggable/client
Type-safe, reactive feature flag SDK for JavaScript, TypeScript, React, and Next.js applications.
Quick Start (Next.js App Router)
1. Install
npm install @flaggable/client @flaggable/react
npm install -D @flaggable/cli
# or
pnpm add @flaggable/client@latest @flaggable/react@latest
pnpm add -D @flaggable/cli@latest
# or
yarn add @flaggable/client @flaggable/react
yarn add --dev @flaggable/cli2. Environment Variables (.env.local)
NEXT_PUBLIC_FLAGGABLE_BASE_URL="http://localhost:3000"
NEXT_PUBLIC_FLAGGABLE_PUBLIC_KEY="pk_your_project_public_key"
FLAGGABLE_INTERNAL_API_KEY="ik_your_internal_api_key"3. Create Client Provider (components/flaggable-provider.tsx)
"use client";
import type { ReactNode } from "react";
import { FlaggableClient } from "@flaggable/client/core";
import { FlaggableProvider } from "@flaggable/react";
export function FlaggableClientProvider({ children }: { children: ReactNode }) {
const publicKey = process.env.NEXT_PUBLIC_FLAGGABLE_PUBLIC_KEY ?? "";
const baseUrl = process.env.NEXT_PUBLIC_FLAGGABLE_BASE_URL;
const flaggableClient = new FlaggableClient({ publicKey, baseUrl });
if (!publicKey) {
return <>{children}</>;
}
return <FlaggableProvider client={flaggableClient}>{children}</FlaggableProvider>;
}4. Wrap Root Layout (app/layout.tsx)
import type { Metadata } from "next";
import { FlaggableClientProvider } from "@/components/flaggable-provider";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<FlaggableClientProvider>{children}</FlaggableClientProvider>
</body>
</html>
);
}5. Use Flags in Any Client Component
"use client";
import { useFlag } from "@flaggable/react";
export function Banner() {
const showBanner = useFlag({ flagName: "show-banner", defaultValue: false });
if (!showBanner) return null;
return (
<div className="bg-orange-500 text-white p-3 rounded text-center">
🎉 Welcome to the new feature!
</div>
);
}API Design: Object Parameters
All Flaggable SDK methods and hooks take object parameters (e.g. useFlag({ flagName, defaultValue }), client.get({ flagName, defaultValue }), client.setEvaluationContext({ context })) rather than positional arguments for clarity, readability, and future extensibility.
React & Next.js Hooks API
See the @flaggable/react package documentation.
FlaggableProvider
Context provider that manages the supplied Flaggable client lifecycle, evaluation caching, and polling.
const flaggableClient = new FlaggableClient({ publicKey: "pk_..." });
<FlaggableProvider client={flaggableClient}>{children}</FlaggableProvider>;useFlag<T>({ flagName, defaultValue, context }): T
React hook returning the reactive value of a feature flag. Automatically re-evaluates when flags change on the server or polling updates.
const isNewCheckout = useFlag({ flagName: "new-checkout", defaultValue: false });
const maxItems = useFlag<number>({ flagName: "cart-limit", defaultValue: 10 });
const brandTheme = useFlag<string>({
flagName: "theme-color",
defaultValue: "blue",
context: { role: "admin" },
});useEvaluate({ context }?)
Hook returning the raw evaluation response payload, loading state, error, and a manual refresh() method.
const { data, error, isLoading, refresh } = useEvaluate();useFlagClient(): FlaggableClient
Accesses the underlying FlaggableClient core instance to manipulate context directly.
const client = useFlagClient();
function handleLogin(user: { id: string; email: string }) {
client.setEvaluationContext({
targetingKey: user.id,
context: { email: user.email },
});
}Core TypeScript / JavaScript Client (@flaggable/client/core)
For Node.js, vanilla browser JS, or non-React frameworks:
import { FlaggableClient } from "@flaggable/client/core";
const flaggableClient = new FlaggableClient({
publicKey: "pk_...",
});
// Single flag evaluation with default
const isEnabled = await flaggable.get({ flagName: "new-feature", defaultValue: false });
// Evaluate all flags
flaggable.setEvaluationContext({ targetingKey: "user_123", context: {} });
const response = await flaggable.evaluate();
console.log(response.evaluations);
// Subscribe to real-time events ('change', 'contextChange', 'error')
const unsubscribe = flaggable.on({
event: "change",
listener: ({ response }) => {
console.log("Flags updated:", response.evaluations);
},
});
// Cleanup
flaggable.destroy();Context & Targeting
The SDK automatically assigns and persists an anonymous ID cookie (flaggable_anonymous_id) in browser environments.
You can supply additional custom attributes for targeting rules (e.g. user ID, role, plan, region):
// Global context on client:
const client = useFlagClient();
client.setEvaluationContext({
context: { env: "staging", team: "core" },
});
// Per-hook context override:
const featureActive = useFlag({
flagName: "beta-flow",
defaultValue: false,
context: {
userId: currentUser.id,
role: currentUser.role,
},
});Type Generation & Schema Safety (flaggable typegen)
Generate end-to-end TypeScript types for all flags in your project. Every value schema must define a JSON Schema default; this is returned when no targeting condition matches. The CLI is a separate development dependency:
npm install -D @flaggable/cli1. Set Internal API Key (.env.local)
FLAGGABLE_INTERNAL_API_KEY="ik_..."2. Run Typegen
npx flaggable typegen
# Or custom output path:
npx flaggable typegen --out ./src/types/flaggable.d.ts3. Autocomplete & Type Inference in React Hooks
Once generated, useFlag and client.get automatically autocomplete flag names and infer expected return types:
// TypeScript autocompletes valid flag names and infers the schema type:
const isEnabled = useFlag({ flagName: "new-checkout-flow", defaultValue: false });
// isEnabled is automatically typed: boolean
const theme = useFlag({ flagName: "theme-color", defaultValue: "dark" });
// theme is automatically typed: "dark" | "light" | "system"Agent Guide & Best Practices
When configuring AI coding agents (Cursor, Claude Code, Pi, Windsurf, Copilot):
- Client Components: Always mark components using
useFlagwith"use client". - Always Provide Defaults: Always pass a realistic default value (
false,"",0, or a default object). - Single Provider: Wrap your application once at the root level (
app/layout.tsxor_app.tsx). Do not nest multipleFlaggableProviders. - Environment Variables: Use
NEXT_PUBLIC_prefix in Next.js so variables are accessible in the browser runtime.
For complete Agent documentation, see docs/agent-guide.md.
