Skip to main content
Technology & EngineeringFeature Flags Services217 lines

ConfigCat

"ConfigCat: feature flags and remote config with percentage rollouts, targeting rules, config-as-code, and cross-platform SDKs"

Quick Summary10 lines
You are an expert in integrating ConfigCat for feature flag management.

## Key Points

- **Define segments for reusable targeting** — instead of duplicating email lists or attribute checks across many flags, create a segment once and reference it in multiple flag rules.
- **Use the config-as-code CLI in CI/CD** — version-control flag definitions by exporting them, reviewing changes in pull requests, and applying updates through your deployment pipeline.
- **Not passing a User object** — without a User, targeting rules and percentage rollouts are skipped entirely, and the flag returns its default value. Always pass at least an identifier.
- **SDK key confusion** — ConfigCat has different SDK keys per environment. Using a production key in staging (or vice versa) silently serves the wrong flag values with no error.
skilldb get feature-flags-services-skills/ConfigCatFull skill: 217 lines
Paste into your CLAUDE.md or agent config

ConfigCat — Feature Flags

You are an expert in integrating ConfigCat for feature flag management.

Core Philosophy

ConfigCat is built on the principle that flag evaluation should happen locally, not over the network. SDKs download the complete configuration JSON once and evaluate flags in-process with zero latency per evaluation. This architecture means your application never blocks on a network call to check a flag, and flags continue to work even when the ConfigCat backend is unreachable. The tradeoff is a propagation delay equal to the polling interval -- acceptable for almost all use cases, but important to understand.

Simplicity is ConfigCat's deliberate design choice. The platform supports boolean flags, text/number settings, targeting rules, percentage rollouts, and segments -- and nothing more. There is no built-in experimentation engine, no event tracking, no analytics dashboard. If you need those features, pair ConfigCat with a separate analytics tool. If you just need reliable feature flags with targeting and gradual rollouts, ConfigCat delivers without the complexity tax of a full feature management platform.

Config-as-code via the CLI and management API means flag definitions can live alongside your application code in version control. Export flags to JSON, review changes in pull requests, and apply updates through CI/CD pipelines. This makes flag management auditable and reversible -- you can trace every flag change to a commit and revert it with git revert.

Anti-Patterns

  • Evaluating flags without passing a User object -- Without a User, all targeting rules and percentage rollouts are skipped. The flag returns its default value, silently disabling every targeted feature.
  • Using AutoPoll in serverless functions -- AutoPoll starts a background timer that does not work in short-lived environments like AWS Lambda. Use ManualPoll and call forceRefreshAsync() once per invocation.
  • Confusing SDK keys across environments -- ConfigCat has different SDK keys for each environment. Using the production key in staging serves production flag values with no error, causing subtle and hard-to-debug behavior differences.
  • Creating duplicate targeting rules across flags instead of using segments -- Repeating the same email list or attribute check in many flags is fragile and hard to maintain. Define a segment once and reference it everywhere.
  • Setting overly long polling intervals -- A 10-minute poll interval means flag changes take up to 10 minutes to propagate. Set intervals based on how quickly you need flag changes to take effect (30-60 seconds is typical).

Overview

ConfigCat is a feature flag and remote configuration service built for simplicity. It supports boolean flags, text/number settings with targeting rules, percentage-based rollouts, and segments. ConfigCat SDKs download the full config JSON and evaluate flags locally — no server round-trips per evaluation. The platform supports config-as-code via a CLI and public management API, making it easy to version-control flag definitions alongside application code.

Setup & Configuration

Node.js Server SDK

import * as configcat from "configcat-node";

const client = configcat.getClient(
  process.env.CONFIGCAT_SDK_KEY!,
  configcat.PollingMode.AutoPoll,
  {
    pollIntervalSeconds: 60,
    logger: configcat.createConsoleLogger(configcat.LogLevel.Warn),
  }
);

// Evaluate a boolean flag
const isEnabled = await client.getValueAsync("newCheckoutFlow", false);

// Evaluate with user targeting
const user = new configcat.User(userId, userEmail, undefined, {
  plan: "enterprise",
  country: "US",
});
const value = await client.getValueAsync("newCheckoutFlow", false, user);

React SDK

import { ConfigCatProvider, useFeatureFlag } from "configcat-react";

function App() {
  return (
    <ConfigCatProvider sdkKey={process.env.REACT_APP_CONFIGCAT_SDK_KEY!}>
      <Dashboard />
    </ConfigCatProvider>
  );
}

function Dashboard() {
  const { value: showBetaBanner, loading } = useFeatureFlag(
    "betaBanner",
    false,
    { identifier: user.id, email: user.email, custom: { plan: user.plan } }
  );

  if (loading) return <Spinner />;
  return showBetaBanner ? <BetaBanner /> : null;
}

Python SDK

import configcatclient

client = configcatclient.get(
    "YOUR_SDK_KEY",
    configcatclient.ConfigCatOptions(
        polling_mode=configcatclient.PollingMode.auto_poll(
            poll_interval_seconds=60
        )
    ),
)

user = configcatclient.User(
    identifier="user-123",
    email="user@example.com",
    custom={"plan": "pro"},
)

is_enabled = client.get_value("newFeature", False, user)

Core Patterns

Targeting Rules

ConfigCat evaluates targeting rules top-to-bottom. The first matching rule wins.

// In the ConfigCat dashboard or config JSON:
// Setting: "pricingVersion" (string)
// Rule 1: IF User.email CONTAINS "@company.com" THEN "v3"
// Rule 2: IF User.custom.plan IS ONE OF ["enterprise"] THEN "v2"
// Default: "v1"

const user = new configcat.User(userId, userEmail, undefined, {
  plan: userPlan,
});

const pricingVersion = await client.getValueAsync("pricingVersion", "v1", user);

switch (pricingVersion) {
  case "v3": return <PricingV3 />;
  case "v2": return <PricingV2 />;
  default:   return <PricingV1 />;
}

Percentage Rollouts

// ConfigCat dashboard config:
// Setting: "experimentGroup" (string)
// Percentage rollout: 50% -> "control", 50% -> "treatment"
// Stickiness is based on User identifier by default

const user = new configcat.User(userId);
const group = await client.getValueAsync("experimentGroup", "control", user);

Segments

// Segments are reusable conditions defined in the ConfigCat dashboard.
// Example segment "BetaTesters":
//   Condition: User.email IS ONE OF ["alice@co.com", "bob@co.com"]
//              OR User.custom.betaOptIn EQUALS "true"
//
// Then in a flag's targeting rules:
//   IF User IS IN SEGMENT "BetaTesters" THEN true
//   Default: false

const user = new configcat.User(userId, userEmail, undefined, {
  betaOptIn: "true",
});
const showBeta = await client.getValueAsync("betaFeature", false, user);

Config-as-Code with CLI

# Install the ConfigCat CLI
npm install -g configcat-cli

# Login
configcat setup --api-user "$CONFIGCAT_API_USER" --api-pass "$CONFIGCAT_API_PASS"

# Export current config to a file
configcat flag-v2 ls --config-id "$CONFIG_ID" --json > flags.json

# Create a new flag
configcat flag-v2 create \
  --config-id "$CONFIG_ID" \
  --name "newFeature" \
  --key "newFeature" \
  --type boolean \
  --hint "Enables the new onboarding flow"

# Update a flag value in a specific environment
configcat flag-v2 value update \
  --flag-id "$FLAG_ID" \
  --environment-id "$ENV_ID" \
  --flag-value true

Polling Modes

// AutoPoll — fetches config at regular intervals (default)
const autoClient = configcat.getClient(sdkKey, configcat.PollingMode.AutoPoll, {
  pollIntervalSeconds: 30,
});

// LazyLoad — fetches config on demand, caches for a TTL
const lazyClient = configcat.getClient(sdkKey, configcat.PollingMode.LazyLoad, {
  cacheTimeToLiveSeconds: 120,
});

// ManualPoll — only fetches when you explicitly call forceRefreshAsync()
const manualClient = configcat.getClient(sdkKey, configcat.PollingMode.ManualPoll);
await manualClient.forceRefreshAsync();
const val = await manualClient.getValueAsync("feature", false);

Best Practices

  • Use ManualPoll in serverless functions — AutoPoll's background timer does not work well in short-lived environments like AWS Lambda. Call forceRefreshAsync() once at the start of each invocation.
  • Define segments for reusable targeting — instead of duplicating email lists or attribute checks across many flags, create a segment once and reference it in multiple flag rules.
  • Use the config-as-code CLI in CI/CD — version-control flag definitions by exporting them, reviewing changes in pull requests, and applying updates through your deployment pipeline.

Common Pitfalls

  • Not passing a User object — without a User, targeting rules and percentage rollouts are skipped entirely, and the flag returns its default value. Always pass at least an identifier.
  • SDK key confusion — ConfigCat has different SDK keys per environment. Using a production key in staging (or vice versa) silently serves the wrong flag values with no error.

Install this skill directly: skilldb add feature-flags-services-skills

Get CLI access →