Skip to Content

Feature Flags

The featureflags package provides feature flag evaluation with support for boolean flags, percentage-based rollouts, user targeting, and multiple flag providers. It enables safe, incremental feature releases.

Import

import "github.com/gofastadev/gofasta/pkg/featureflags"

Key Types

FlagManager

type FlagManager interface { IsEnabled(ctx context.Context, flag string) bool IsEnabledFor(ctx context.Context, flag string, userID string) bool GetVariant(ctx context.Context, flag string, userID string) string AllFlags(ctx context.Context) map[string]Flag Refresh(ctx context.Context) error }

Flag

type Flag struct { Name string `json:"name"` Enabled bool `json:"enabled"` Description string `json:"description"` Percentage float64 `json:"percentage,omitempty"` Variants []Variant `json:"variants,omitempty"` AllowList []string `json:"allow_list,omitempty"` DenyList []string `json:"deny_list,omitempty"` }

Variant

type Variant struct { Name string `json:"name"` Weight float64 `json:"weight"` }

FlagConfig

type FlagConfig struct { Provider string `yaml:"provider" env:"FLAGS_PROVIDER"` FilePath string `yaml:"file_path" env:"FLAGS_FILE_PATH"` RefreshRate time.Duration `yaml:"refresh_rate" env:"FLAGS_REFRESH_RATE"` Endpoint string `yaml:"endpoint" env:"FLAGS_ENDPOINT"` }

Key Functions

FunctionSignatureDescription
NewFlagManagerfunc NewFlagManager(cfg FlagConfig) (FlagManager, error)Creates a flag manager using the configured provider
NewFileFlagProviderfunc NewFileFlagProvider(path string) (FlagManager, error)Loads flags from a JSON/YAML file
NewHTTPFlagProviderfunc NewHTTPFlagProvider(endpoint string, refreshRate time.Duration) (FlagManager, error)Loads flags from a remote HTTP endpoint
Middlewarefunc Middleware(fm FlagManager) func(http.Handler) http.HandlerInjects the flag manager into the request context
FromContextfunc FromContext(ctx context.Context) FlagManagerRetrieves the flag manager from context

Flag Definition File

flags.yaml:

flags: new_dashboard: enabled: true description: "New dashboard UI" percentage: 50 allow_list: - "user-123" - "user-456" dark_mode: enabled: true description: "Dark mode support" checkout_v2: enabled: true description: "New checkout flow" variants: - name: control weight: 50 - name: variant_a weight: 30 - name: variant_b weight: 20

Usage

Basic Flag Checking

fm, err := featureflags.NewFlagManager(featureflags.FlagConfig{ Provider: "file", FilePath: "flags.yaml", }) if err != nil { log.Fatalf("failed to load flags: %v", err) } if fm.IsEnabled(ctx, "dark_mode") { // serve dark mode UI }

User-Targeted Flags

// Percentage rollout -- deterministic per user if fm.IsEnabledFor(ctx, "new_dashboard", userID) { // show new dashboard } // Users in the allow_list always see the feature // fm.IsEnabledFor(ctx, "new_dashboard", "user-123") -> true

A/B Testing with Variants

variant := fm.GetVariant(ctx, "checkout_v2", userID) switch variant { case "variant_a": // show variant A case "variant_b": // show variant B default: // show control }

Using in Controllers

func (c *DashboardController) Index(w http.ResponseWriter, r *http.Request) { fm := featureflags.FromContext(r.Context()) claims := auth.ClaimsFromContext(r.Context()) if fm.IsEnabledFor(r.Context(), "new_dashboard", claims.UserID) { httputil.JSON(w, http.StatusOK, newDashboardData) return } httputil.JSON(w, http.StatusOK, legacyDashboardData) }

Refreshing Flags

Flags loaded from an HTTP provider are refreshed automatically at the configured interval. You can also trigger a manual refresh.

err := fm.Refresh(ctx)

Configuration via config.yaml

feature_flags: provider: file # "file" or "http" file_path: flags.yaml refresh_rate: 30s
Last updated on