Skip to main content
Technology & EngineeringFeature Flags Services289 lines

Flipt

"Flipt: open-source, self-hosted feature flag platform with GitOps support, boolean and multivariate flags, and GRPC/REST APIs"

Quick Summary12 lines
You are an expert in integrating Flipt for feature flag management.

## Key Points

- key: dark-mode
- key: checkout-experiment
- key: beta-testers
- key: all-users
- **Separate namespaces per team or domain** — namespaces prevent flag key collisions and let teams manage their own flags independently without affecting others.
- **Use batch evaluation when checking multiple flags** — a single batch request reduces network round-trips compared to individual calls, especially important when Flipt runs as a remote service.
skilldb get feature-flags-services-skills/FliptFull skill: 289 lines
Paste into your CLAUDE.md or agent config

Flipt — Feature Flags

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

Core Philosophy

Flipt exists for teams that want feature flags without vendor lock-in. It is fully open-source, self-hosted, and requires nothing beyond a database (even SQLite for small deployments). You own the data, control the infrastructure, and never worry about per-seat pricing, usage limits, or a third-party SaaS going down. The tradeoff is operational responsibility: you manage the deployment, backups, and availability of the Flipt service.

GitOps is the recommended way to manage flags in production. Flipt can sync flag definitions from a Git repository, making every flag change a pull request that is reviewable, auditable, and reversible. Developers propose flag changes in YAML, reviewers approve them, and Flipt's Git backend polls the repository and applies updates automatically. This workflow eliminates the risk of ad-hoc dashboard changes that no one can trace or undo.

Namespaces provide isolation without infrastructure duplication. Instead of running separate Flipt instances for each team or domain, use namespaces to partition flag definitions so that team A's flags cannot collide with or affect team B's flags. Combined with the API's namespace-scoped evaluation, this makes Flipt suitable for multi-team organizations without the cost of per-team infrastructure.

Anti-Patterns

  • Forgetting to set enabled: true on a flag -- A flag can have fully configured rules and rollouts, but if the top-level enabled field is false, it always evaluates to its default (false for booleans, no variant). This is the most common "my flag isn't working" debugging issue.
  • Using inconsistent entity IDs for the same user -- Percentage rollouts are deterministic based on entityId + flagKey. Passing email for one request and UUID for another means the same user gets inconsistent treatment assignments.
  • Making individual evaluation calls when batch evaluation is available -- Each evaluation is a network round-trip to the Flipt server. When checking multiple flags per request, use batch evaluation to reduce latency.
  • Running Flipt without a durable database in production -- SQLite is fine for development, but production deployments should use PostgreSQL or MySQL for durability, backups, and concurrent access.
  • Skipping the Git backend in favor of dashboard-only management -- Dashboard changes are convenient but unauditable. Without Git history, you cannot trace who changed a flag, when, or why -- and you cannot revert safely.

Overview

Flipt is an open-source, self-hosted feature flag platform that requires no external dependencies beyond a database. It supports boolean flags, multivariate flags with variants, percentage-based rollouts, segment-based targeting, and namespaces for multi-tenant or multi-team isolation. Flipt offers both gRPC and REST APIs, a built-in web UI, and a GitOps-native workflow where flag definitions can live in Git repositories and be synced declaratively. There is no SaaS vendor dependency — you own the entire stack.

Setup & Configuration

Self-Hosted Deployment

# docker-compose.yml
version: "3.9"
services:
  flipt:
    image: flipt/flipt:latest
    ports:
      - "8080:8080"   # HTTP API + UI
      - "9000:9000"   # gRPC API
    volumes:
      - ./flipt-config.yml:/etc/flipt/config.yml
      - flipt_data:/var/opt/flipt
    environment:
      FLIPT_LOG_LEVEL: info
      FLIPT_DB_URL: "file:/var/opt/flipt/flipt.db"  # SQLite default

volumes:
  flipt_data:

Node.js SDK (REST)

import { FliptClient } from "@flipt-io/flipt";

const flipt = new FliptClient({
  url: process.env.FLIPT_URL || "http://localhost:8080",
  authToken: process.env.FLIPT_AUTH_TOKEN,
});

// Boolean flag evaluation
const boolResult = await flipt.evaluation.boolean({
  namespaceKey: "default",
  flagKey: "dark-mode",
  entityId: user.id,
  context: {
    plan: user.plan,
    region: user.region,
  },
});

if (boolResult.enabled) {
  enableDarkMode();
}

// Variant flag evaluation
const variantResult = await flipt.evaluation.variant({
  namespaceKey: "default",
  flagKey: "checkout-experiment",
  entityId: user.id,
  context: {
    country: user.country,
  },
});

// variantResult.variantKey: "control" | "streamlined" | "minimal"
renderCheckout(variantResult.variantKey);

Go SDK

package main

import (
    "context"
    "log"
    "os"

    flipt "go.flipt.io/flipt/sdk/go"
    flipthttp "go.flipt.io/flipt/sdk/go/http"
)

func main() {
    client := flipt.New(
        flipthttp.NewTransport(os.Getenv("FLIPT_URL")),
    )

    result, err := client.Evaluation().Boolean(context.Background(), &flipt.EvaluationRequest{
        NamespaceKey: "default",
        FlagKey:      "new-algorithm",
        EntityId:     "user-123",
        Context: map[string]string{
            "tier": "premium",
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    if result.Enabled {
        useNewAlgorithm()
    }
}

Core Patterns

GitOps — Flags as Code

Flipt can sync flag definitions from a Git repository, making flags version-controlled and reviewable via pull requests.

# .flipt.yml at repo root — tells Flipt where to find flag definitions
version: "1.0"

# features/flags.yml
namespace: default
flags:
  - key: dark-mode
    name: Dark Mode
    type: BOOLEAN_FLAG_TYPE
    enabled: true
    rollouts:
      - segment:
          key: beta-testers
          value: true
      - threshold:
          percentage: 25
          value: true

  - key: checkout-experiment
    name: Checkout Experiment
    type: VARIANT_FLAG_TYPE
    enabled: true
    variants:
      - key: control
        name: Control
      - key: streamlined
        name: Streamlined Flow
      - key: minimal
        name: Minimal Flow
    rules:
      - segment: all-users
        distributions:
          - variant: control
            rollout: 50
          - variant: streamlined
            rollout: 30
          - variant: minimal
            rollout: 20

segments:
  - key: beta-testers
    name: Beta Testers
    match_type: ANY_MATCH_TYPE
    constraints:
      - type: STRING_COMPARISON_TYPE
        property: plan
        operator: eq
        value: "enterprise"

  - key: all-users
    name: All Users
    match_type: ALL_MATCH_TYPE
# Flipt config to enable Git backend
# /etc/flipt/config.yml
storage:
  type: git
  git:
    repository: https://github.com/your-org/feature-flags.git
    ref: main
    poll_interval: 30s
    authentication:
      token:
        access_token: ${GITHUB_TOKEN}

Namespaces for Multi-Team Isolation

// Team A flags
const teamAResult = await flipt.evaluation.boolean({
  namespaceKey: "team-payments",
  flagKey: "stripe-v2",
  entityId: user.id,
  context: {},
});

// Team B flags — completely isolated
const teamBResult = await flipt.evaluation.boolean({
  namespaceKey: "team-notifications",
  flagKey: "email-batching",
  entityId: user.id,
  context: {},
});

Batch Evaluation

const batchResult = await flipt.evaluation.batch({
  requests: [
    {
      namespaceKey: "default",
      flagKey: "dark-mode",
      entityId: user.id,
      context: { plan: user.plan },
    },
    {
      namespaceKey: "default",
      flagKey: "checkout-experiment",
      entityId: user.id,
      context: { country: user.country },
    },
    {
      namespaceKey: "default",
      flagKey: "new-pricing",
      entityId: user.id,
      context: {},
    },
  ],
});

// batchResult.responses is an array matching the request order
const [darkMode, checkout, pricing] = batchResult.responses;

REST API Direct Usage

# Evaluate a boolean flag
curl -X POST http://localhost:8080/evaluate/v1/boolean \
  -H "Content-Type: application/json" \
  -d '{
    "namespaceKey": "default",
    "flagKey": "dark-mode",
    "entityId": "user-123",
    "context": {"plan": "pro"}
  }'

# Evaluate a variant flag
curl -X POST http://localhost:8080/evaluate/v1/variant \
  -H "Content-Type: application/json" \
  -d '{
    "namespaceKey": "default",
    "flagKey": "checkout-experiment",
    "entityId": "user-123",
    "context": {"country": "US"}
  }'

Best Practices

  • Use GitOps for production flag management — storing flag definitions in Git gives you version history, pull request reviews, and rollback via git revert. The Flipt Git backend polls automatically.
  • Separate namespaces per team or domain — namespaces prevent flag key collisions and let teams manage their own flags independently without affecting others.
  • Use batch evaluation when checking multiple flags — a single batch request reduces network round-trips compared to individual calls, especially important when Flipt runs as a remote service.

Common Pitfalls

  • Forgetting to set enabled: true on the flag — a flag can have rules and rollouts configured, but if the top-level enabled field is false, the flag always evaluates to its default (false for booleans, no variant for variant flags).
  • Entity ID inconsistency — percentage rollouts are deterministic based on entityId + flagKey. If you pass different identifiers for the same user across requests (e.g., sometimes email, sometimes UUID), the user gets inconsistent treatment assignments.

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

Get CLI access →