Skip to main content
Feature flags let you control who sees what features in your product. Ship code to production safely, test with internal users, and gradually roll out to everyone without redeploying.

How it works

Feature flags wrap new code behind a conditional check:
// Check if feature is enabled for this user
if (posthog.isFeatureEnabled('new-dashboard')) {
  // Show new dashboard
  showNewDashboard()
} else {
  // Show old dashboard
  showOldDashboard()
}
PostHog evaluates the flag based on your rollout rules and returns true or false instantly.

Creating a flag

Create flags from the feature flags page:
1

Click New feature flag

Navigate to Feature flags and click New feature flag.
2

Configure the flag

  • Key: Unique identifier (e.g., new-checkout-flow)
  • Name: Human-readable name
  • Description: What this flag controls
3

Set rollout rules

Choose your rollout strategy:
  • Roll out to everyone (100%)
  • Roll out to a percentage (e.g., 10% of users)
  • Target specific users by properties
  • Use multiple conditions with AND/OR logic
4

Save and activate

Save the flag and toggle it active. Your code can now check this flag.

Rollout strategies

Release to a percentage of users:
  • Set rollout to 10% initially
  • Monitor metrics for issues
  • Increase to 25%, then 50%, then 100%
  • Roll back to 0% instantly if problems arise
PostHog uses consistent hashing. The same users always see the feature at each percentage level.

Using flags in code

Check flags across platforms:
// Simple boolean check
if (posthog.isFeatureEnabled('new-dashboard')) {
  renderNewDashboard()
}

// With callback (waits for flag to load)
posthog.onFeatureFlags(() => {
  if (posthog.isFeatureEnabled('new-dashboard')) {
    renderNewDashboard()
  }
})

// Get all flags at once
const flags = posthog.getFeatureFlags()
console.log(flags) // ['new-dashboard', 'dark-mode', ...]

Multivariate flags

Return different values instead of just true/false:
// Create a multivariate flag with variants:
// - control (50%)
// - variant-a (25%)
// - variant-b (25%)

const variant = posthog.getFeatureFlag('checkout-test')

switch (variant) {
  case 'variant-a':
    showCheckoutFlowA()
    break
  case 'variant-b':
    showCheckoutFlowB()
    break
  default:
    showDefaultCheckout()
}
Use multivariate flags for A/B tests with more than 2 variants.

Bootstrapping flags

Avoid flicker by loading flags on the server:
// Server-side: fetch flags for the user
const flags = await posthog.getAllFlags('user_distinct_id')

// Send to client
res.render('index', { featureFlags: flags })

// Client-side: bootstrap PostHog with flags
posthog.init('<ph_project_api_key>', {
  bootstrap: {
    featureFlags: <%= JSON.stringify(featureFlags) %>
  }
})

// Flags are available immediately, no loading state
if (posthog.isFeatureEnabled('new-dashboard')) {
  renderNewDashboard()
}

Local evaluation

Evaluate flags on your server for faster performance:
from posthog import Posthog

posthog = Posthog(
  '<ph_project_api_key>',
  host='<ph_instance_address>',
  personal_api_key='<ph_personal_api_key>'  # Required for local evaluation
)

# Flags are evaluated locally, no API call
is_enabled = posthog.feature_enabled(
  'new-dashboard',
  'user_distinct_id',
  person_properties={'plan': 'enterprise'}
)
Local evaluation caches flag definitions and evaluates them in your process. Latency drops from approximately 50ms to less than 1ms.

Early access features

Let users opt in to beta features:
1

Create an early access feature

  1. Go to Feature flagsEarly access
  2. Click New early access feature
  3. Link to an existing feature flag
  4. Add a name and description
2

Show opt-in UI

// Get available early access features
const features = posthog.getEarlyAccessFeatures()

// Show UI for users to opt in
features.forEach(feature => {
  console.log(feature.name, feature.description)
})

// User opts in
posthog.updateEarlyAccessFeatureEnrollment(
  'feature-key',
  true  // enrolled
)
3

Flag activates automatically

Once enrolled, the linked feature flag returns true for that user.

Common workflows

Safe deployment

Wrap new code in a flag set to 0%. Deploy to production with feature disabled. Test internally by enabling for your team, then gradually roll out.

Kill switch

If a feature causes issues, set rollout to 0% instantly. No code deployment needed. Fix the issue and re-enable when ready.

Beta program

Create a flag targeting users with beta_user = true. Let users opt into beta features via your settings page.

Sunsetting features

Before removing code, set flag to 0% for a week. If no complaints, the feature wasn’t being used. Safe to delete.

Flag analytics

Track flag performance:
  • Usage dashboard: See which flags are active and their rollout percentage
  • Event tracking: PostHog automatically tracks $feature_flag_called events
  • Correlation analysis: See if flag variants correlate with conversion or retention
Create insights filtering by $feature_flag property to compare metrics across flag states.

Best practices

Make feature flags your default deployment strategy. The ability to roll back instantly is worth the small code overhead.
After a feature is fully rolled out and stable, remove the flag from code. Keep your codebase clean of unused conditionals.
Use descriptive names like new-checkout-flow not flag-123. Your future self will thank you.
Before rolling out, test flag logic by setting your user properties to match your targeting rules. Verify the flag returns the expected value.
Use the description field to explain what the flag controls and when it can be removed. Helps with cleanup later.

Build docs developers (and LLMs) love