Feature flags in TypeScript: how to enable features without deployment

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

When deployment is a pain: why developers love feature flags

\n\n

Imagine: you've been working on a new feature for a week. You covered it with tests, ran code review, hit the deploy button. And then — boom! — everything breaks in production. Users are furious, the manager is twitching, you're frantically rolling back the version. Sound familiar?

\n\n

Now imagine a different scenario: you enable the new feature for only 5% of users. You watch the metrics. You see everything is fine. Gradually increase the percentage to 100%. No stress, no rollbacks, just calm confidence.

\n\n

This is the magic of feature flags (also known as feature toggles). In TypeScript projects, this technique is especially great thanks to static typing and strict type control. Today we'll figure out how to implement feature flags in your project so you can sleep soundly and features can be enabled without pain.

\n\n

What are feature flags in simple terms

\n\n

A feature flag is a conditional switch in the code that allows you to enable or disable functionality without changing the code or redeploying. It looks something like this:

\n\n
if (featureFlags.isEnabled('new-checkout')) {\n  // new code\n} else {\n  // old code\n}\n
\n\n

Everything ingenious is simple, right? But behind this simplicity lies a powerful tool used by Google, Netflix, Facebook, and other giants. They don't deploy every little thing — they manage application behavior through a centralized control panel.

\n\n

When feature flags are really needed

\n\n
    \n
  • Canary release — rolling out a new feature to a small portion of users
  • \n
  • Dark launch — hidden testing, where the feature exists but users don't see it
  • \n
  • A/B testing — comparing two versions of functionality
  • \n
  • Kill switch — emergency disabling of problematic code without deployment
  • \n
  • Permit testing — testing on internal users or by roles
  • \n
\n\n

In TypeScript projects, feature flags take on a special charm: the compiler checks that you're using flags correctly, not confusing types, and not forgetting to handle all states.

\n\n

Architecture of a feature flag system

\n\n

Before writing code, let's figure out what a well-designed feature management system consists of.

\n\n

Basic components

\n\n
    \n
  1. Flag storage — where the values are stored (JSON, database, external service)
  2. \n
  3. Provider — a module that loads and caches flags
  4. \n
  5. Client side — code that checks the state of flags
  6. \n
  7. Control panel — interface for changing flags in real time
  8. \n
\n\n

Simplest implementation in TypeScript

\n\n

Let's start with the most basic example. Let's create a type for flags and a simple service:

\n\n
// types/feature-flags.ts\nexport type FeatureFlag = \n  | 'new-checkout'\n  | 'dark-mode'\n  | 'recommendations-v2'\n  | 'beta-chat';\n\nexport interface FeatureFlagConfig {\n  flag: FeatureFlag;\n  enabled: boolean;\n  rolloutPercentage?: number;\n  userIds?: string[];\n}\n
\n\n

Now let's write the service itself:

\n\n
// services/feature-flag.service.ts\nexport class FeatureFlagService {\n  private flags: Map<FeatureFlag, FeatureFlagConfig> = new Map();\n\n  constructor(initialFlags: FeatureFlagConfig[]) {\n    initialFlags.forEach(flag => {\n      this.flags.set(flag.flag, flag);\n    });\n  }\n\n  isEnabled(flag: FeatureFlag, userId?: string): boolean {\n    const config = this.flags.get(flag);\n    if (!config) return false;\n\n    if (!config.enabled) return false;\n\n    // Check by specific users\n    if (config.userIds && userId) {\n      return config.userIds.includes(userId);\n    }\n\n    // Rollout by percent                

Blogs

Book Recommendations