# Bootstrap Feature Flags - Docs

Bootstrapping Feature Flags makes precomputed flag values available as soon as a client-side PostHog SDK initializes. This prevents flicker and enables startup logic, such as redirects, to use flags before the SDK finishes its first `/flags` request.

This page covers feature flag-specific behavior. See [bootstrapping PostHog SDKs](/docs/libraries/bootstrapping.md) for identity, session, persistence, and cross-SDK behavior.

> **Note:** Feature flag bootstrapping is available in the [JavaScript web](/docs/libraries/js.md), [React Native](/docs/libraries/react-native.md), [iOS](/docs/libraries/ios.md), [Android](/docs/libraries/android.md), and [Flutter](/docs/libraries/flutter.md) SDKs.

## Bootstrap flag values

Pass known flag values to `bootstrap.featureFlags` during SDK initialization:

### Web

```javascript
posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2026-05-30',
    bootstrap: {
        featureFlags: {
            'new-checkout': true,
            'checkout-variant': 'test',
        },
    },
})
```

### React Native

```jsx
<PostHogProvider
    apiKey="<ph_project_token>"
    options={{
        host: 'https://us.i.posthog.com',
        bootstrap: {
            featureFlags: {
                'new-checkout': true,
                'checkout-variant': 'test',
            },
        },
    }}
>
    <MyApp />
</PostHogProvider>
```

### Swift

```swift
let config = PostHogConfig(projectToken: "<ph_project_token>", host: "https://us.i.posthog.com")
config.bootstrap = PostHogBootstrapConfig(
    featureFlags: [
        "new-checkout": true,
        "checkout-variant": "test"
    ],
    featureFlagPayloads: nil
)
PostHogSDK.shared.setup(config)
```

### Kotlin

```kotlin
val config = PostHogAndroidConfig(apiKey = "<ph_project_token>", host = "https://us.i.posthog.com")
config.bootstrap = PostHogBootstrapConfig(
    featureFlags = mapOf(
        "new-checkout" to true,
        "checkout-variant" to "test"
    )
)
PostHogAndroid.setup(this, config)
```

### Dart

```dart
final config = PostHogConfig('<ph_project_token>');
config.host = 'https://us.i.posthog.com';
config.bootstrap = PostHogBootstrapConfig(
  featureFlags: {
    'new-checkout': true,
    'checkout-variant': 'test',
  },
);
await Posthog().setup(config);
```

You can also seed JSON-serializable payloads with `featureFlagPayloads`:

### Web

```javascript
posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2026-05-30',
    bootstrap: {
        featureFlags: {
            'checkout-variant': 'test',
        },
        featureFlagPayloads: {
            'checkout-variant': {
                buttonText: 'Try the new checkout',
            },
        },
    },
})
```

## Get the correct values from your server

For web apps, evaluate flags on your server as part of the page request, then pass the results to the client:

1.  Get or create the distinct ID the client uses.
2.  Call [`getAllFlags()`](/docs/feature-flags/adding-feature-flag-code?tab=Node.js.md#fetching-all-flags-for-a-user) for that distinct ID on your server.
3.  Include the flag values and distinct ID in the response that renders the page.
4.  Pass both values to `bootstrap` when the client initializes PostHog.

Use `posthog-node`'s `getAllFlagsAndPayloads()` instead when you also need payloads. Use [server-side local evaluation](/docs/feature-flags/local-evaluation.md) to avoid a network request to PostHog while handling the page request.

For mobile apps, get the server-evaluated values before SDK setup and pass them to `PostHogBootstrapConfig`.

### Use the same distinct ID on the server and client

Percentage rollout and variant assignment are deterministic for a distinct ID. If the server evaluates flags with one ID and the client initializes with another, the client can receive a different value when it fetches flags. Keep person properties, group properties, and [evaluation contexts](/docs/feature-flags/evaluation-contexts.md) consistent too when your flag uses them.

Bootstrap the same ID you used for server-side evaluation:

### Web

```javascript
posthog.init('<ph_project_token>', {
    api_host: 'https://us.i.posthog.com',
    defaults: '2026-05-30',
    bootstrap: {
        distinctID: 'distinct_id_used_on_the_server',
        isIdentifiedID: true,
        featureFlags: serverEvaluatedFlags,
    },
})
```

See [bootstrapping an identity](/docs/libraries/bootstrapping.md#bootstrap-an-identity) for anonymous IDs, identified IDs, and persisted identity reconciliation.

## Understand the flag lifecycle

Bootstrapped flags seed the SDK's initial state. They don't permanently override values from PostHog.

-   The SDK serves bootstrapped values immediately.
-   The next complete `/flags` response replaces the complete set of bootstrapped values. Keys that only exist in the bootstrap configuration are removed.
-   A partial or errored response updates the flags it computed and preserves previous values for the others.
-   Calling `reset()` clears bootstrapped flags.
-   If you disable automatic feature flag requests, no `/flags` response replaces the bootstrapped values. Use `updateFlags()` to supply new values at runtime in SDKs that support it.

Bootstrapping only seeds enabled flags. Use `true` for a boolean flag or a non-empty string for a multivariate flag. The SDK drops `false` and empty values. See [mobile SDK bootstrapping behavior](/docs/libraries/bootstrapping.md#behavior-on-mobile-sdks) for persistence and first-launch behavior.

## Bootstrap flags in single-page apps

In environments where `posthog.init()` runs once during a session, such as a single-page app using Next.js `instrumentation-client`, choose one of these approaches:

-   **Server-side pre-evaluation** – Evaluate flags before the app renders, then pass the values into the app and add them to `bootstrap` or use them directly.
-   **Client-side pre-evaluation** – Evaluate the flag in an earlier page or state than the one where you need it, then store and reuse it.

Both approaches prevent flicker as long as the server and client use the same distinct ID.

## Override flags instead of bootstrapping

Use overrides when you need to replace flag values after initialization or keep a value from being replaced by `/flags`. Bootstrapping is for initial state, not persistent overrides.

### Node.js

```javascript
posthog.overrideFeatureFlags({ 'new-checkout': true })
```

### Web

```javascript
posthog.featureFlags.overrideFeatureFlags({
    flags: { 'checkout-variant': 'test' },
    payloads: { 'checkout-variant': { buttonText: 'Try the new checkout' } },
})
```

## Examples

-   [How to bootstrap feature flags in React and Express](/tutorials/bootstrap-feature-flags-react.md)
-   [How to use Next.js middleware to bootstrap feature flags](/tutorials/nextjs-bootstrap-flags.md)
-   [How to set up Next.js A/B tests](/tutorials/nextjs-ab-tests.md)

### Still have questions?

Ask PostHog AI
