Skip to main content

Feature Flags in SaaS Boilerplates

·StarterPick Team
feature-flagsposthoglaunchdarklysaas2026

TL;DR

PostHog for most indie SaaS — generous free tier (1M events/month), combines analytics + feature flags + session recording in one platform. LaunchDarkly for enterprise SaaS where feature flags are a core product requirement (targeting rules, experiments, audit logs). Custom implementation for simple on/off flags without targeting rules. PostHog replaces 3-4 separate tools.

Why Feature Flags Matter

Feature flags decouple deployment from release:

Without flags:        Deploy → Feature is live for everyone
With flags:           Deploy → Feature off → Gradually enable by segment
                               (internal testers → beta users → 10% → 50% → 100%)

Use cases:

  • Canary releases — Roll out to 5% of users, monitor metrics, then expand
  • Beta access — "Pro plan users get early access to this feature"
  • A/B testing — Show variant A to 50%, variant B to 50%, measure conversion
  • Kill switches — Instantly disable a broken feature without redeployment
  • Gradual rollout — Region by region, or cohort by cohort

PostHog: Analytics + Flags + Session Recording

PostHog combines analytics, feature flags, session recording, and A/B testing in one platform. The free tier is generous enough for most indie SaaS.

// lib/posthog.ts
import PostHog from 'posthog-node';

export const posthog = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  host: process.env.NEXT_PUBLIC_POSTHOG_HOST!,
});

// Server-side flag evaluation
export async function isFeatureEnabled(
  flag: string,
  userId: string,
  properties?: Record<string, any>
): Promise<boolean> {
  return posthog.isFeatureEnabled(flag, userId, { personProperties: properties });
}
// Client-side flag usage
'use client';
import { useFeatureFlagEnabled } from 'posthog-js/react';

export function Dashboard() {
  const isNewDashboardEnabled = useFeatureFlagEnabled('new-dashboard-v2');

  return (
    <div>
      {isNewDashboardEnabled ? (
        <NewDashboardLayout />  // Beta feature
      ) : (
        <OldDashboardLayout />  // Stable fallback
      )}
    </div>
  );
}
// Server Component flag check
import { isFeatureEnabled } from '@/lib/posthog';

async function BillingPage({ userId }: { userId: string }) {
  const [isAnnualPlanEnabled, user] = await Promise.all([
    isFeatureEnabled('annual-billing', userId),
    getUser(userId),
  ]);

  return (
    <div>
      <MonthlyPlan />
      {isAnnualPlanEnabled && <AnnualPlan />}  // Only show to flag-enabled users
    </div>
  );
}

PostHog Flag Targeting Rules

PostHog allows complex targeting via their UI:

Flag: "new-ai-features"
├── Enable for: users where plan = "pro" (100%)
├── Enable for: users where email ends in @yourcompany.com (100%)
├── Enable for: users where created_at > 2025-01-01 (50%)
└── Everyone else: false

No code changes needed to adjust rollout percentage or targeting rules.


LaunchDarkly: Enterprise Feature Management

LaunchDarkly is purpose-built for feature flags at enterprise scale. Rich SDK, audit logging, RBAC for flag management, unlimited targeting complexity.

import LaunchDarkly from '@launchdarkly/node-server-sdk';

const ldClient = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY!);
await ldClient.waitForInitialization();

// Context-based evaluation (LaunchDarkly v6+)
async function checkFlag(flagKey: string, userId: string, orgId: string) {
  const context = {
    kind: 'multi',
    user: { key: userId, plan: 'pro' },
    organization: { key: orgId, tier: 'enterprise' },
  };

  return ldClient.variation(flagKey, context, false);
}

// Flag with JSON payload (return config objects, not just booleans)
const searchConfig = await ldClient.variation(
  'search-algorithm-config',
  context,
  { algorithm: 'keyword', maxResults: 10 }  // Default
);
// searchConfig could be: { algorithm: 'semantic', maxResults: 25, model: 'v3' }

LaunchDarkly Advantages

  • Experiments: Proper A/B testing with statistical significance
  • Scheduled releases: Set a date/time to automatically enable a flag
  • Audit trail: Every flag change logged with who changed it and when
  • RBAC: Different teams can manage different flags
  • JSON flags: Return complex configuration objects, not just booleans

LaunchDarkly Pricing

Starter: $10/seat/month. For a 3-person team: $30/month. Reasonable for enterprise B2B SaaS where flag management is a business requirement.


Custom Feature Flags (Simplest Option)

For basic on/off flags without targeting rules:

// lib/features.ts — simplest possible feature flags
const features = {
  NEW_BILLING_UI: process.env.FEATURE_NEW_BILLING_UI === 'true',
  AI_ASSISTANT: process.env.FEATURE_AI_ASSISTANT === 'true',
  BETA_API: process.env.FEATURE_BETA_API === 'true',
} as const;

export function isEnabled(feature: keyof typeof features): boolean {
  return features[feature];
}
import { isEnabled } from '@/lib/features';

function Settings() {
  return (
    <div>
      {isEnabled('NEW_BILLING_UI') && <NewBillingSettings />}
    </div>
  );
}

When this is enough:

  • Internal flags (dev vs prod differences)
  • Simple on/off without per-user targeting
  • Early stage with no need for gradual rollout

When to upgrade to PostHog/LaunchDarkly:

  • Need per-user or per-plan targeting
  • Need gradual percentage rollout
  • Need to track which users saw which version

Boilerplate Feature Flag Support

BoilerplateFeature FlagsProvider
ShipFast
Supastarter
Makerkit✅ OptionalPostHog
T3 Stack
Open SaaSPostHog

Find boilerplates with analytics and feature flags on StarterPick.

Check out this boilerplate

View PostHog on StarterPick →

Comments