top of page

Feature Flags for Solo Builders: Ship Safely Without a DevOps Team

Writer: kate frese
kate frese
Aug 21
7 min read

Updated: Aug 22


Why Solo Builders Need Feature Flags More Than Big Teams

Feature flags (or feature toggles) are conditional statements in your code that allow you to turn functionality on or off dynamically at runtime without deploying new code.


Large engineering teams have staging environments, dedicated QA testers, site reliability engineers (SREs), and automated canary deployments. When a release breaks production in a large company, an entire team mobilizes to triage, rollback, and patch the bug.


When you run a solo software company, you are the developer, QA team, SRE, and on-call engineer rolled into one. If an unhandled edge case crashes your web app or mobile application at 2:00 AM, you don't have a team to handle the crisis. Rolling back code via Git, triggering a 15-minute CI/CD build, or submitting an emergency app store patch means real downtime, angry customers, and tanked app ratings.


Feature flags flip that dynamic. With a flag, mitigating a production failure takes less than two seconds: you flip a switch, the bad code branch is bypassed, and your app falls back to a safe state instantly.


More importantly, feature flags decouple code deployment from feature exposure. You can deploy code to production whenever it is ready—even on a Friday afternoon—and choose exactly when and to whom that code becomes visible.


The 3 Essential Types of Feature Flags

Not all flags serve the same purpose. Understanding the three primary patterns helps you keep your architecture clean and targeted.

1. Release Flags (Dark Launching)

Release flags allow you to merge code into your main branch and ship it to production long before it's launched to the public.

  • Goal: Eliminate long-lived Git branches and enable true continuous integration.

  • How it works: You wrap a new feature in a flag that defaults to false. The code lives in production, but no user executes it except you (by targeting your admin account). You test in the real production environment against live database connections, then flip the flag to true for all users when you're ready.


2. Experiment Flags (A/B Testing)

Experiment flags route users into different code paths based on rules or deterministic hashing.

  • Goal: Test product hypotheses with real user behavior instead of guessing.

  • How it works: You assign half your traffic to Variant A and half to Variant B. By logging conversion metrics for each variant, you make data-backed product decisions without writing complex custom branching infrastructure.


3. Ops Flags (Kill Switches)

Ops flags protect system reliability, external API rate limits, and database health under unexpected load.

  • Goal: Operational protection and graceful degradation.

  • How it works: You wrap resource-heavy features—like an AI generation tool, a complex export function, or a third-party integration—behind an operational kill switch. If an external service drops or database CPU spikes, you toggle off the high-impact feature without taking down the rest of your application.


Practical Examples: Flags in Action

Here is how feature flags solve real solo-builder problems across three common scenarios:

Dark-Launching a New Checkout Flow

You are rewriting your payment integration to support new payment methods. Instead of keeping a risky git branch open for three weeks, you ship the new checkout components behind a flag:

// Server-side flag check if (await isFeatureEnabled('stripe_checkout_v2', user.id)) { return renderNewCheckout(user); } else { return renderLegacyCheckout(user); }

You enable stripe_checkout_v2 for only your own user ID in production. You run test transactions, verify webhooks, and ensure database entries align. Once verified, you roll it out to 10% of real users, monitor conversion, and scale to 100%.

Killing a Crashing Feature Remotely

A new rich-text editor feature in your app triggers an unexpected memory leak on mobile Safari. Your inbox starts filling up with support tickets.

Without feature flags, you would need to hotfix the code, push a release, and wait for deployment or mobile review approval. With an ops flag wrapping the editor component:

// Toggling off rich text editor falls back to standard text area {isFeatureEnabled('rich_text_editor') ? ( <RichTextEditor value={content} onChange={setContent} /> ) : ( <StandardTextArea value={content} onChange={setContent} /> )}

You flip rich_text_editor to false in your remote config. Instantly, all users see the standard text area, the crash stops, and you fix the leak in local development without pressure.

Testing Two Onboarding Flows

You want to know if a shorter 2-step onboarding screen yields higher paid trial conversions than your current 5-step questionnaire.

const variant = getExperimentVariant('onboarding_v2', user.id); if (variant === 'short_form') { return <QuickOnboardingStep user={user} />; } return <FullOnboardingStep user={user} />;

You track trial starts by variant over two weeks, determine the winning screen, and convert 100% of traffic to the winner.


DIY Feature Flags: Zero-SaaS Implementation

You do not need a paid monthly subscription to start using feature flags today. You can build simple, robust flag evaluations yourself using three basic patterns.

Level 1: Environment Variables (Static Toggles)

Best for infrastructure gates or global features that change only during deployments.

// config/flags.js export const FLAGS = { ENABLE_AI_ASSISTANT: process.env.ENABLE_AI_ASSISTANT === 'true', ENABLE_NEW_PRICING: process.env.ENABLE_NEW_PRICING === 'true', };

  • Pros: Zero setup time, zero external dependencies.

  • Cons: Requires a server restart or deployment to change states.

Level 2: Remote JSON Config (Dynamic Toggles)

Store a JSON file on object storage (like S3) or a public CDN endpoint. Your app fetches or polls this file every 60 seconds and caches it in memory.

{ "new_search_engine": true, "beta_user_ids": ["usr_8812", "usr_9934"], "checkout_rollout_pct": 25 }

// Simple flag reader with caching let cachedFlags = {}; async function refreshFlags() { try { const res = await fetch('https://cdn.yourdomain.com/flags.json'); cachedFlags = await res.json(); } catch (err) { console.error('Failed to fetch flags, using cached fallback', err); } } // Refresh flags every minute setInterval(refreshFlags, 60000);

  • Pros: Toggle features dynamically across your entire application in under a minute without re-deploying code.

  • Cons: Basic targeting only; no granular user segments out of the box.

Level 3: Database Table with Percentage Rollouts

Create a simple database table for flags that supports user targeting and percentage-based rollouts.

Database Schema (feature_flags):

  • key (text, primary key)

  • enabled (boolean)

  • rollout_percentage (integer, 0-100)

  • allowed_user_ids (text array)

Deterministic Hash Function for Percentage Rollouts: To ensure a user always gets a consistent experience (so they don't flip between Variant A and B on every page refresh), use deterministic hashing:

import crypto from 'crypto'; function isUserInRollout(userId, flagKey, percentage) { if (percentage <= 0) return false; if (percentage >= 100) return true; // Hash user ID + flag key to get a stable score between 0 and 99 const hash = crypto.createHash('md5').update(${userId}:${flagKey}).digest('hex'); const score = parseInt(hash.substring(0, 8), 16) % 100; return score < percentage; } export async function evaluateFlag(flagKey, user) { const flag = await db.featureFlags.findByKey(flagKey); if (!flag || !flag.enabled) return false; // Check specific user allowlist first if (flag.allowed_user_ids?.includes(user.id)) return true; // Fallback to percentage rollout return isUserInRollout(user.id, flagKey, flag.rollout_percentage); }

When to Graduate to a Dedicated Tool

Building your own flag system works well for 1 to 5 active flags. However, as your product grows, maintaining home-grown flag evaluation logic can become a distraction.

Consider graduating to a managed feature flag platform (such as LaunchDarkly, PostHog, GrowthBook, or Unleash) when you need:

  • Complex Targeting Rules: Targeting users based on multi-attribute rules (e.g., Plan == Pro AND Country == US AND AccountAge > 30 days).

  • Built-in Analytics Integration: Automatically connecting flag variants to conversion events and calculating statistical significance.

  • Cross-Platform SDKs: Syncing flag states seamlessly across web, iOS, Android, and backend services with automatic offline caching.

  • Audit Logging: Detailed history of who changed a flag, when it was changed, and what value it held.

Tip for solo builders: Platforms like PostHog offer feature flags alongside product analytics in a generous free tier, making them ideal for single-developer stacks.


The #1 Mistake: Flags as Permanent Configuration

The single biggest mistake solo builders make with feature flags is treating them as permanent settings.

Every feature flag adds an if/else conditional branch to your codebase. If you leave flags in your code after a feature is fully launched, your codebase rapidly degrades into a web of dead branches, untested code permutations, and confusing logic.

Feature flags are temporary rollout mechanisms, not permanent system configurations.

  • Use Environment Variables / App Settings for long-term system configurations (e.g., API keys, rate limits, tier limits).

  • Use Feature Flags strictly for temporary code changes that have a defined beginning and end.

Once a feature reaches 100% rollout and proves stable in production for 14 to 30 days, the flag has fulfilled its purpose. You must delete it.


The 5-Step Safe Flag Lifecycle

Treating feature flags as short-lived tasks keeps your codebase clean and your rollouts controlled:

  1. Create: Define the flag with a clear, specific name (checkout_stripe_v2), a default safe value (false), and set a scheduled cleanup date in your task manager.

  2. Test & Dark Launch (0% Public / Admin Only): Ship the code to production. Enable the flag only for your personal admin user ID. Verify functionality against live data.

  3. Canary Rollout (5% - 10%): Enable the flag for a small percentage of users. Monitor error logs, database query performance, and support tickets for 24 to 48 hours.

  4. Expand to 100%: Gradually step up exposure (25% → 50% → 100%) as your confidence grows.

  5. Remove Flag & Clean Up: Once fully rolled out and stable, submit a quick PR that removes the if/else flag wrapper, deletes the old legacy code path, and archived the flag in your database or tool.


Checklist for Safe Solo Flag Usage

Use this checklist before and during every feature flag rollout:

  • ☐ Descriptive Naming: Flag key clearly states what it controls (e.g., onboarding_v2_short_form).

  • ☐ Safe Default Fallback: Code handles flag lookup failures or network timeouts gracefully by defaulting to the existing, working code path.

  • ☐ Deterministic User Hashing: Rollouts use a hash of the user ID so users receive a consistent variant across sessions and devices.

  • ☐ Logging & Monitoring: Critical operations behind flags log execution errors to your error tracker (e.g., Sentry) so you notice failures instantly.

  • ☐ Cleanup Task Created: A calendar reminder or issue ticket is scheduled to remove the flag within 30 days of 100% rollout.

  • ☐ Kill Switch Verification: For high-impact operational flags, you have manually tested flipping the flag to false to confirm the app degrades safely without breaking.


Closing

You don't need a DevOps team, a complex Kubernetes cluster, or an SRE department to ship software safely and confidently every day. Feature flags give solo builders total control over the deployment lifecycle, eliminating deployment anxiety and protecting your production environment.

Your Actionable Takeaway: Pick one feature or UI update you are currently working on locally. Instead of holding it in an unmerged branch, wrap it in a simple 5-line conditional check, default it to false, and merge it to main today. Practice dark launching your code into production before you turn it on for users.


Disclaimer

This post is published by BlueVioletApps LLC for informational and educational purposes only and reflects general software development practices. It does not constitute legal, technical, or consulting advice. Tools and platforms referenced are examples only — evaluate and test all tooling in your own environment before adoption. BlueVioletApps LLC is an independent software development firm and is not affiliated with, endorsed by, or officially connected to any platform or vendor referenced herein.

Comments


with_padding (5).png

Blue Violet Security architectures are designed for NIST 800-53 alignment and CMMC 2.0 Level 2 readiness. Our commitment to secure, PII-safe environments is the foundation of every Fleet solution.

  • Instagram
  • Facebook
  • LinkedIn
  • BlueVioletApps, LLC

  • Status: (Verified SDVOSB) / Woman-Owned Small Business (Certification Pending)

  • SAM.gov UEI: L2YYBMHWGQC8

BlueVioletApps, LLC respects your privacy. We do not sell user data. All information collected via demo requests is used solely for professional outreach and is handled in accordance with our PII-safe architecture standards designed for NIST 800-53 alignment.

bottom of page