flagsmith-js-client
The official JavaScript and React Native client SDK for Flagsmith, the open source feature flag and remote configuration platform.
Repository Health
Technical Analysis
Flagsmith’s JavaScript client is the SDK that connects web, SSR, and React Native applications to the Flagsmith feature-flagging and remote-config API. A single core module (flagsmith-core.ts) implements flag/trait fetching, caching, and change detection, while separate platform entry points wire in the right fetch, storage, and realtime-streaming implementation for the browser, Node/SSR, and React Native.
Beyond simple on/off toggles, the client supports identity-scoped traits, multivariate flag variants, local default flags for offline/fallback behavior, cached flag state with configurable TTLs, and realtime flag updates over server-sent events so UI can react to flag changes without a page reload. First-class React bindings (FlagsmithProvider plus hooks) let components subscribe to flag state without manually wiring subscriptions.
It integrates with Sentry and Datadog RUM for correlating feature-flag exposure with errors and session data, and ships an opt-in analytics/event-exposure pipeline for tracking which flags and variants users actually saw. The package is published as @flagsmith/flagsmith for web/SSR and a sibling @flagsmith/react-native package for mobile, both generated from the same core via a Rollup build.
What You Get
- A single default
flagsmithinstance pluscreateFlagsmithInstance()for multi-tenant or test scenarios - Platform-specific entry points for browser, SSR/isomorphic, and React Native that share one evaluation core
- React bindings —
FlagsmithProviderand hooks likeuseFlagsmithLoading— for subscribing to flag state declaratively - Realtime flag updates over server-sent events (via
reconnecting-eventsourceon web,react-native-sseon mobile) - Identity/trait-aware evaluation with local default flags, response caching, and configurable cache TTLs
- Optional integrations with Sentry and Datadog RUM to correlate flag exposure with errors and sessions
Common Use Cases
- Gating a new feature behind a flag and rolling it out gradually to a percentage of users
- Serving different remote-config values (pricing tiers, copy, limits) per user segment without a redeploy
- Running A/B or multivariate experiments using flag variants and correlating them with product analytics
- Rendering server-side with SSR-fetched flag state that hydrates into the client without a flash of default content
- Using React Native/mobile apps to fetch and cache flags for offline-tolerant feature gating
Under The Hood
Architecture
The library centers on a single core factory function (core() in flagsmith-core.ts, the largest file in the repo) that returns a Flagsmith class instance configured with platform-specific dependencies: an AsyncStorage implementation, a fetch-like function, and an EventSource constructor. Separate entry points — index.ts (browser/SSR, using unfetch), isomorphic.ts (SSR/edge, no bundled fetch polyfill), index.react-native.ts (wiring react-native-sse), and next-middleware.ts (a bare config variant) — each inject a different combination of these dependencies into the same core, keeping evaluation and state-management logic centralized while letting thin adapters vary by runtime. React bindings (react.tsx) wrap a core instance in a FlagsmithContext/FlagsmithProvider and expose hooks that subscribe to an internal Emitter (utils/emitter.ts) for change notifications, decoupling the vanilla-JS core from React’s render cycle. An EventProcessor (event-processor.ts) implements an opt-in, feature-gated analytics/exposure pipeline. State diffing uses fast-deep-equal (via utils/get-changes.ts) to compute changed flags/traits before firing onChange callbacks, and an EvaluationContext type (generated with quicktype from a JSON schema pulled from the main Flagsmith server repo) models identity and traits for context-based evaluation. Because every platform entry point and the React layer depend directly on the core’s exported factory and IFlagsmith interface, changes to the core cascade to all consumers at once.
Tech Stack
Written entirely in TypeScript and bundled with Rollup (rollup.config.js) plus a custom move-react.js script and rollup-plugin-dts, producing two published packages (@flagsmith/flagsmith and a React Native sibling) from one source tree. Runtime dependencies are deliberately minimal — isomorphic-unfetch/unfetch for cross-environment fetch, reconnecting-eventsource and react-native-sse for realtime SSE streams, and fast-deep-equal for change detection — with patch-package applying local patches to a dependency on install. There is no backend or database; the SDK is purely a client for the hosted or self-hosted Flagsmith REST/SSE API (defaulting to edge.api.flagsmith.com).
Code Quality
The repo carries an extensive Jest test suite (20+ spec files) covering caching, default flags, event processing, isomorphic behavior, React hooks and variants, Sentry integration, trait-key casing, type resolution, and reason codes, run with ts-jest/Babel and a jsdom environment for the React specs. ESLint extends eslint:recommended, plugin:react/recommended, plugin:react-hooks/recommended, and @typescript-eslint/recommended, enforced through a Husky pre-commit hook alongside a tsc type-check, so type and lint errors are caught before a commit lands. Types are modeled comprehensively in types.d.ts with generic parameters for flag/trait key literal types, giving consumers strong autocomplete; a small number of @ts-ignore/@ts-expect-error casts bridge platform-specific globals like EventSource and window. CI runs via GitHub Actions, and releases are automated with release-please.
API Design
The public surface is intentionally small: a default singleton instance for the common case, createFlagsmithInstance() for multi-instance or test scenarios, and a FlagsmithProvider component plus hooks for React consumers — genuinely low boilerplate for the common “init once, read everywhere” pattern. Method names (hasFeature, getValue, getTrait, getAllFlags) read naturally, and options objects (GetValueOptions, HasFeatureOptions) keep call sites terse while still exposing skipAnalytics/json/fallback knobs for edge cases. The platform-specific entry points mean most consumers never see the underlying config differences (storage, event-source shims) directly. Primary documentation lives on an external docs site rather than inline, and newer capabilities like the events pipeline are explicitly marked experimental/internal in the type comments, signaling an evolving surface.