For the complete documentation index, see llms.txt. Prefer markdown by appending .md to documentation URLs or sending Accept: text/markdown.

Usage

Evaluate feature flags in Expo screens, sync targeting context from auth, and add new flag keys to TurboStarter mobile.

Once a provider is active, reading a flag is a one-liner with OpenFeature hooks from @workspace/flags.

Flag keys

Keys live in one place so web, mobile, and extension stay aligned:

packages/flags/shared/src/keys.ts
export const Flag = {
  DEMO: "demo",
} as const;

Import Flag from @workspace/flags and pass the constant into hooks.

Evaluate in a screen

import { Flag, useBooleanFlagValue } from "@workspace/flags";
import { Text } from "@workspace/ui-mobile/text";

export const BetaBadge = () => {
  const enabled = useBooleanFlagValue(Flag.DEMO, false);

  if (!enabled) {
    return null;
  }

  return <Text>Beta features unlocked</Text>;
};

The settings screen uses the same pattern for the demo banner:

apps/mobile/src/app/dashboard/(user)/settings/index.tsx
const demo = useBooleanFlagValue(Flag.DEMO, false);

Other value types:

HookTypical use
useBooleanFlagValueOn/off gates
useStringFlagValueVariant copy, theme names, deep links
useNumberFlagValueLimits, percentages, experiment arms
useObjectFlagValueStructured payloads / config blobs

Always pass a sensible default as the second argument. That value is used while the provider loads, or if evaluation fails.

Targeting context

apps/mobile/src/lib/providers/flags.tsx already syncs auth state into OpenFeature:

apps/mobile/src/lib/providers/flags.tsx
if (session.data?.user) {
  const { id, email, name } = session.data.user;
  void setContext({ targetingKey: id, email, name });
  return;
}

void clearContext();

You rarely need to call setContext / clearContext yourself. Import them from @workspace/flags-mobile when you do.

With PostHog, context sync identifies the person and reloads feature flags so cohort rules apply promptly after sign-in.

Add a new flag

Declare the key

Add a constant in packages/flags/shared/src/keys.ts:

export const Flag = {
  DEMO: "demo",
  NEW_ONBOARDING: "NEW_ONBOARDING", 
} as const;

Update in-memory defaults

Give local development a known value in packages/flags/shared/src/in-memory.ts:

[Flag.NEW_ONBOARDING]: {
  disabled: false,
  variants: { on: true, off: false },
  defaultVariant: "off",
},

Create it remotely (if needed)

In PostHog or GrowthBook, create a flag with the same key (NEW_ONBOARDING). Configure rollouts and targeting there.

Evaluate it in a screen

const showOnboarding = useBooleanFlagValue(Flag.NEW_ONBOARDING, false);

Troubleshooting

SymptomWhat to check
Demo banner never appearsIn-memory defaultVariant is "on" by default. For PostHog/GrowthBook, ensure a remote flag named demo exists and targets your user.
Flag stuck on the defaultConfirm the provider export in packages/flags/mobile/src/providers/index.ts matches the env vars you set. Restart Metro after env changes.
Remote rules ignore the userSign in so targetingKey is set. With PostHog, wait for flags to reload after identify.
Wrong env prefixMobile uses EXPO_PUBLIC_POSTHOG_* / EXPO_PUBLIC_GROWTHBOOK_*, not NEXT_PUBLIC_ or VITE_.

How is this guide?

Last updated on

On this page

Ship your startup everywhere. In minutes.Try TurboStarter