Feature Flag User Guide
A practical guide to every flag type and targeting scenario supported by GoGreen Flags, with dashboard configuration steps and SDK code examples.
Core Concepts
| Concept | Description |
|---|---|
| Flag | A named toggle with one or more variations. Identified by a unique key (e.g. new-checkout). |
| Variation | A possible value a flag can return. Boolean flags have two (true/false); other types can have many. |
| Rule | A targeting condition. Rules contain clauses (AND logic) and an optional rollout strategy. Evaluated top-to-bottom by priority. |
| Clause | A single condition: attribute operator value(s). Multiple clauses in a rule are ANDed together. |
| Segment | A reusable group of users, defined by rules or an explicit list. Referenced via the segment_match operator. |
| Environment | An isolated evaluation context (e.g. Development, Staging, Production). Each has its own rules, SDK key, and rollout schedule. |
| Evaluation Context | The user or entity being evaluated. Has a key (unique ID) and custom attributes (e.g. email, country, plan). |
| Default Value | The fallthrough value returned when no rules match and the flag is enabled. |
| Off Variation | The value returned when the flag is disabled. |
Evaluation Order
1. Is the flag enabled?
No → return Off Variation (reason: OFF)
Yes → continue
2. Are all prerequisites met?
No → return Off Variation (reason: PREREQUISITE_FAILED)
Yes → continue
3. Evaluate rules in priority order (top to bottom):
Rule matches → apply rollout strategy or return variation (reason: RULE_MATCH)
4. No rules matched → return Default value (reason: DEFAULT)Getting Started
Install the SDK
Go:
go get github.com/gogreen/sdk-goTypeScript / Node.js:
npm install @gogreenflags/sdkInitialize the Client
Go:
package main
import (
"log"
"time"
gogreen "github.com/gogreen/sdk-go"
shared "github.com/gogreen/shared-data"
)
func main() {
client, err := gogreen.NewClient(gogreen.Config{
SDKKey: "sdk_your_key_here",
EnvID: "env_your_env_id",
APIBaseURL: "https://app.gogreenflags.com",
StreamURL: "https://app.gogreenflags.com",
EventsURL: "https://app.gogreenflags.com",
EnableStreaming: true,
PollInterval: 30 * time.Second,
})
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
if err := client.WaitForInitialization(10 * time.Second); err != nil {
log.Printf("Warning: SDK not yet initialized: %v", err)
}
user := shared.EvaluationContext{
Key: "user-42",
Custom: map[string]interface{}{
"email": "alice@example.com",
"country": "US",
"plan": "pro",
},
}
enabled := client.BoolVariation("new-checkout", user, false)
log.Printf("new-checkout = %v", enabled)
}TypeScript (CommonJS — for ESM projects see SDK Reference):
import { GoGreenClient } from '@gogreenflags/sdk';
const client = new GoGreenClient({
sdkKey: 'sdk_your_key_here',
environmentId: 'env_your_env_id',
apiBaseUrl: 'https://app.gogreenflags.com',
streamUrl: 'https://app.gogreenflags.com',
eventsUrl: 'https://app.gogreenflags.com',
enableStreaming: true,
defaultContext: {
key: 'user-42',
custom: {
email: 'alice@example.com',
country: 'US',
plan: 'pro',
},
},
});
await client.waitForInitialization();
const enabled = await client.boolVariation('new-checkout', false);
console.log('new-checkout =', enabled);Where to Find Your SDK Key
- Open the GoGreen Flags dashboard
- Go to Project Settings → Environments
- Expand the target environment (e.g. “Production”)
- Copy the SDK Key (client-side) or Server Key (server-side)
Flag Types
Boolean Flags
The most common type. Returns true or false.
When to use: Feature toggles, kill switches, opt-in features, two-variant A/B tests.
Dashboard setup:
- Click Create Flag
- Set Key:
new-checkout - Set Type: Boolean
- Two variations are created automatically:
trueandfalse
SDK usage:
// Go — synchronous, returns from local config
enabled := client.BoolVariation("new-checkout", user, false)
if enabled {
showNewCheckout()
} else {
showOldCheckout()
}// TypeScript — async
const enabled = await client.boolVariation('new-checkout', false);With evaluation detail:
val, detail := client.BoolVariationDetail("new-checkout", user, false)
log.Printf("Value: %v, Reason: %s, Rule: %v", val, detail.Reason.Kind, detail.RuleIndex)
// Value: true, Reason: RULE_MATCH, Rule: 0const detail = await client.boolVariationDetail('new-checkout', false);
console.log(`Value: ${detail.value}, Reason: ${detail.reason}`);String Flags
Returns a string value. Useful for selecting between named variants.
When to use: Theme selection, algorithm variants, banner copy, locale-specific messages.
Dashboard setup:
- Create flag with Type: String
- Add variations:
control="classic",treatment-a="modern",treatment-b="minimal" - Set the Default to
"classic"
theme := client.StringVariation("checkout-theme", user, "classic")
switch theme {
case "modern":
renderModernCheckout()
case "minimal":
renderMinimalCheckout()
default:
renderClassicCheckout()
}const theme = await client.stringVariation('checkout-theme', 'classic');Number Flags
Returns a numeric value (float64). Useful for tuning parameters without redeploying.
When to use: Rate limits, timeout values, retry counts, cache TTLs, discount percentages.
Dashboard setup:
- Create flag with Type: Number
- Add variations:
low=100,medium=500,high=2000
rateLimit := client.NumberVariation("api-rate-limit", user, 100)
limiter.SetLimit(rateLimit)const rateLimit = await client.numberVariation('api-rate-limit', 100);JSON Flags
Returns a structured JSON object. The most flexible type.
When to use: UI layout configs, experiment parameters, feature bundles, dynamic form schemas.
Dashboard setup:
- Create flag with Type: JSON
- Add variations with JSON values, for example:
compact:{"layout": "single-column", "showSidebar": false, "maxItems": 10}full:{"layout": "two-column", "showSidebar": true, "maxItems": 50}
config := client.JSONVariation("dashboard-layout", user, defaultCfg)
if cfg, ok := config.(map[string]interface{}); ok {
layout := cfg["layout"].(string)
renderDashboard(layout)
}const config = await client.jsonVariation('dashboard-layout', {
layout: 'single-column',
showSidebar: false,
maxItems: 10,
});Targeting Scenarios
Kill Switch (Global On/Off)
The flag is either on or off for everyone. No targeting rules needed.
When to use: Emergency shutoff, maintenance mode, global feature launch.
Dashboard: Toggle the flag’s enabled switch. Set the Off Variation to false.
if client.BoolVariation("maintenance-mode", user, false) {
http.Error(w, "System under maintenance", http.StatusServiceUnavailable)
return
}if (await client.boolVariation('maintenance-mode', false)) {
return res.status(503).json({ message: 'System under maintenance' });
}User Targeting (Individual Users)
Target specific users by their unique key.
When to use: Internal dogfooding, individual opt-in, VIP access, debugging.
Dashboard:
- Add a Rule → Clause:
keyequser-42,user-99 - Serve:
true
alice := shared.EvaluationContext{Key: "user-42"} // matches → true
bob := shared.EvaluationContext{Key: "user-999"} // no match → defaultAttribute-Based Targeting
Target users based on custom attributes like email, country, or plan.
When to use: Geo-targeting, plan-based features, internal users, email domain filtering.
Dashboard — Example: Pro plan users in the US:
- Add a rule with two clauses (AND):
planeqprocountryeqUS
- Serve:
true
Dashboard — Example: Internal users by email domain:
- Rule:
emailends_with@company.com - Serve:
true
user := shared.EvaluationContext{
Key: "user-42",
Custom: map[string]interface{}{
"email": "alice@company.com",
"country": "US",
"plan": "pro",
},
}
enabled := client.BoolVariation("us-pro-feature", user, false) // trueconst enabled = await client.boolVariation('us-pro-feature', false, {
key: 'user-42',
custom: { email: 'alice@company.com', country: 'US', plan: 'pro' },
});Negation: Any clause can be negated by toggling the Negate option, which inverts the result. For example, country eq US with negate means “country is NOT US”.
Segment Targeting
Target pre-defined groups of users using reusable segments.
When to use: Beta testers, enterprise customers, QA teams, geographic regions.
Dashboard:
- Create a segment (see Segments section below)
- In the flag rule, add clause:
segment_match=beta-testers - Serve: the desired variation
// Segment membership is evaluated locally from cached config.
// No extra API call is needed.
user := shared.EvaluationContext{
Key: "user-42",
Custom: map[string]interface{}{"plan": "enterprise"},
}
enabled := client.BoolVariation("beta-feature", user, false)Percentage Rollout
Gradually release a feature to a percentage of users. The assignment is deterministic — the same user always gets the same variation (based on MurmurHash3 of flagKey.userKey.salt).
When to use: Gradual feature release, A/B testing, canary deployments, risk mitigation.
Dashboard:
- Open flag → Rules → Add rule
- Under Serve, select Percentage Rollout
- Set distribution:
true10%,false90%
The hash algorithm provides 0.01% precision (10,000 buckets).
// ~10% get true, ~90% get false. Same user always gets the same result.
enabled := client.BoolVariation("new-algorithm", user, false)Multi-variation percentage rollout (string flag):
control: 50%
treatment-a: 30%
treatment-b: 20%variant := client.StringVariation("checkout-experiment", user, "control")Gradual Rollout Schedule
Automatically ramp a percentage rollout over time without manual intervention.
When to use: Multi-day feature launches, time-gated releases, automated canary progression.
Dashboard:
- Open flag → Gradual rollout schedule card
- Click Create gradual rollout schedule
- Select the Target variation (e.g. the
truevariation) - Define steps:
| Step | Percentage | Delay until next |
|---|---|---|
| 1 | 1% | 60 minutes |
| 2 | 10% | 120 minutes |
| 3 | 50% | 240 minutes |
| 4 | 100% | 0 minutes |
- Click Start gradual rollout
The system automatically advances to the next step after each delay. The dashboard shows current step, status (active, paused, completed), and next advance time.
Controls:
- Rollback: Revert to the previous step if issues are detected
- Delete schedule: Stop automatic advancement
No SDK changes needed — the rollout schedule updates the underlying percentage on the server. The SDK receives updated config via streaming/polling.
// At t=0: ~1% of users get true
// At t=60m: ~10% get true
// At t=180m: ~50% get true
// At t=420m: 100% get true
enabled := client.BoolVariation("new-feature", user, false)Multi-Variate (A/B/n Testing)
Test more than two variants simultaneously using string, number, or JSON flags.
When to use: Testing multiple UI designs, pricing strategies, algorithm variants.
Dashboard:
- Create a string flag
pricing-pagewith 4 variations:original,simplified,comparison-table,interactive-calculator - Add a rule with Percentage Rollout: 25% each
- Optionally create an Experiment linked to this flag to track metrics
variant := client.StringVariation("pricing-page", user, "original")
switch variant {
case "simplified":
renderSimplifiedPricing()
case "comparison-table":
renderComparisonTable()
case "interactive-calculator":
renderInteractiveCalculator()
default:
renderOriginalPricing()
}
// Track conversion
client.Track("pricing_page_signup", user, map[string]any{
"variant": variant,
"revenue": 29.99,
})const variant = await client.stringVariation('pricing-page', 'original');
client.track('pricing_page_signup', { variant, revenue: 29.99 });Prerequisites (Flag Dependencies)
Make a flag depend on another flag’s value. The dependent flag returns its off variation unless all prerequisites are met.
When to use: Feature chains (B requires A), tiered rollouts, coordinated launches.
Dashboard:
- Open the dependent flag (e.g.
advanced-analytics) - Add a Prerequisite: Flag =
basic-analytics, Required variation =true - Save
Now advanced-analytics only evaluates if basic-analytics returns true for the same user.
val, detail := client.BoolVariationDetail("advanced-analytics", user, false)
if detail.Reason.Kind == "PREREQUISITE_FAILED" {
log.Printf("Blocked by prerequisite: %s", detail.Reason.PrerequisiteKey)
}Prerequisites are checked recursively (max 10 levels). Circular dependencies are rejected at save time.
Canary Release
Release to a small percentage first, monitor, then increase.
When to use: Risky deployments, infrastructure changes, database migrations behind a flag.
Manual canary:
- Create boolean flag → percentage rollout: 1%
true, 99%false - Monitor metrics and errors
- Manually increase: 1% → 5% → 25% → 100%
Automated canary (gradual rollout):
- Use a Gradual rollout schedule: 1% (30m) → 5% (60m) → 25% (120m) → 100%
- If errors spike, click Rollback to previous step
if client.BoolVariation("new-payment-processor", user, false) {
result, err := newProcessor.Charge(amount)
if err != nil {
metrics.IncrCounter("payment.new_processor.errors", 1)
}
} else {
result, err := oldProcessor.Charge(amount)
}Ring-Based Deployment
Use segments to define deployment rings: internal → beta → early adopters → everyone.
When to use: Enterprise rollouts, platform migrations, structured validation at each ring.
Dashboard:
- Create segments:
ring-0-internal: list-based (employee user IDs)ring-1-beta: list-based (beta program members)ring-2-early-adopters: rule-based (planeqenterprise)
- Add rules in priority order:
| Priority | Rule | Serve |
|---|---|---|
| 1 | segment_match = ring-0-internal | true |
| 2 | segment_match = ring-1-beta | true |
| 3 | segment_match = ring-2-early-adopters | true |
- Default:
false - Enable each ring progressively by toggling the rule’s
enabledstate
Time-Based Targeting
Target users based on timestamps using the before and after operators (RFC 3339 format).
When to use: Scheduled launches, time-limited promotions, sunset dates.
Dashboard:
- Rule:
launch_timeafter2026-04-01T00:00:00Z - Serve:
true
user := shared.EvaluationContext{
Key: "user-42",
Custom: map[string]interface{}{
"launch_time": time.Now().Format(time.RFC3339),
},
}
enabled := client.BoolVariation("spring-sale", user, false)Pass the current time as a custom attribute so the evaluation engine can compare against the rule.
Semver-Based Targeting
Target users based on their app or SDK version using semantic version operators.
When to use: Feature gating by client version, forcing minimum versions, deprecating old clients.
Dashboard — Enable for apps >= v2.5.0:
- Rule:
app_versionsemver_gte2.5.0 - Serve:
true
user := shared.EvaluationContext{
Key: "user-42",
Custom: map[string]interface{}{"app_version": "2.7.1"},
}
enabled := client.BoolVariation("new-api-v2", user, false) // trueThe v prefix is stripped automatically — both v2.5.0 and 2.5.0 work.
Segments
Segments are reusable groups of users referenced across multiple flags.
Rule-Based Segments
Membership determined dynamically by evaluating clauses against user attributes.
When to use: Groups defined by characteristics (enterprise customers, European users, users on a specific plan).
Dashboard:
- Segments → Create Segment
- Key:
enterprise-customers, Type: Rule-based - Add constraints:
planeqenterprise - Save
Preview membership: In segment detail → Targeting Rules tab → enter user keys in Preview matched users → click Preview. Shows a table of which keys match.
List-Based Segments
Membership is an explicit, fixed list of user keys.
When to use: Beta program members, specific accounts, employee IDs, test accounts.
Dashboard:
- Create segment with Type: List-based
- In Included Members tab:
- Manual: Type a user key and click Add
- CSV upload: One key per line
- JSON upload: JSON array of keys
- Supports up to 1M entries via file upload (stream-processed server-side)
Environments
Environments isolate flag configuration. Each environment has its own targeting rules, rollout schedules, SDK key, and server key.
Typical setup:
| Environment | Purpose |
|---|---|
| Development | Local dev, all flags on |
| Staging | Pre-production testing |
| Production | Live users, protected |
SDK per environment:
// Production
client, _ := gogreen.NewClient(gogreen.Config{
SDKKey: "sdk_prod_abc123",
EnvID: "env_production_id",
})
// Staging
client, _ := gogreen.NewClient(gogreen.Config{
SDKKey: "sdk_stg_xyz789",
EnvID: "env_staging_id",
})Key rotation: Use the Rotate keys button in Environment Settings. Update your SDK configuration with the new key and redeploy.
Lifecycle Types
Organize flags by purpose to keep your flag inventory healthy.
| Type | Description | Staleness |
|---|---|---|
release | Standard feature release. Remove after full rollout. | Flagged as stale after extended time at 100% |
experiment | A/B test flag. Remove after experiment concludes. | Stale when experiment is stopped |
ops | Operational toggle (kill switch, circuit breaker). | May be long-lived |
permission | Access control toggle (feature tier, RBAC). | Long-lived by design |
permanent | Explicitly marked as never stale. | Never flagged |
The dashboard highlights stale flags so you can clean them up.
Experimentation
Link a flag to an experiment to measure the impact of different variations.
Dashboard:
- Create a multi-variation flag
- Experiments → Create Experiment
- Configure: name, feature flag, baseline variation, metrics (event type + aggregation)
- Click Start Experiment
Track events:
client.Track("pricing_page_signup", user, map[string]any{"revenue": 29.99})client.track('pricing_page_signup', { revenue: 29.99 });The experimentation service computes results (winner, confidence, p-value) displayed in the dashboard.
Production Safeguards
Environment Protection
Require approval before changes go live in production.
Dashboard: Project Settings → Environments → Protection:
- Require approval: On
- Minimum reviewers: 1+
- Allow flag owner to approve: On/Off
- Auto-expire hours: Optional
Diff Modal
When saving changes in a production environment, a diff modal shows JSON before/after and requires a mandatory comment.
Audit Log
All changes logged in the Audit Log with filtering by date, actor, action, and resource. Export as CSV for compliance.
OpenFeature Integration
GoGreen Flags provides an OpenFeature provider for vendor-neutral flag evaluation.
Go:
import (
gogreen "github.com/gogreen/sdk-go"
"github.com/open-feature/go-sdk/openfeature"
)
ggClient, _ := gogreen.NewClient(gogreen.Config{
SDKKey: "sdk_your_key", EnvID: "env_your_id",
APIBaseURL: "https://app.gogreenflags.com",
})
defer ggClient.Close()
provider := gogreen.NewGoGreenProvider(ggClient)
openfeature.SetProvider(provider)
ofClient := openfeature.NewClient("my-app")
evalCtx := openfeature.NewEvaluationContext("user-42", map[string]interface{}{
"email": "alice@example.com",
})
enabled, _ := ofClient.BooleanValue(ctx, "new-checkout", false, evalCtx)TypeScript:
import { GoGreenClient } from '@gogreenflags/sdk';
import { GoGreenProvider } from '@gogreenflags/sdk/provider';
import { OpenFeature } from '@openfeature/server-sdk';
const ggClient = new GoGreenClient({ sdkKey: 'sdk_your_key', environmentId: 'env_id', defaultContext: { key: 'anonymous' } });
await OpenFeature.setProviderAndWait(new GoGreenProvider(ggClient));
const ofClient = OpenFeature.getClient('my-app');
const enabled = await ofClient.getBooleanValue('new-checkout', false, { targetingKey: 'user-42' });React Integration
The TypeScript SDK includes a React provider and useFeatureFlag hook.
import { GoGreenProvider, useFeatureFlag } from '@gogreenflags/sdk/react';
function App() {
return (
<GoGreenProvider config={{
sdkKey: 'sdk_your_client_key',
environmentId: 'env_your_id',
apiBaseUrl: 'https://app.gogreenflags.com',
enableStreaming: true,
defaultContext: { key: currentUser.id, custom: { email: currentUser.email } },
}}>
<MyApp />
</GoGreenProvider>
);
}
function CheckoutPage() {
const { value: useNewCheckout, loading } = useFeatureFlag('new-checkout', false);
if (loading) return <Spinner />;
return useNewCheckout ? <NewCheckout /> : <ClassicCheckout />;
}Testing with Feature Flags
Test Client
Both SDKs provide a test client that returns predetermined values without network calls.
Go:
client := gogreen.NewTestClient(map[string]interface{}{
"new-checkout": true,
"checkout-theme": "modern",
"rate-limit": 500.0,
})
defer client.Close()
val := client.BoolVariation("new-checkout", user, false) // trueTypeScript:
const client = GoGreenClient.testClient({
'new-checkout': true,
'checkout-theme': 'modern',
});
const enabled = await client.boolVariation('new-checkout', false); // trueBootstrap & Offline Mode
Pre-load flag values for integration tests:
client, _ := gogreen.NewClient(gogreen.Config{
SDKKey: "test-key", EnvID: "test-env", Offline: true,
BootstrapConfig: &shared.EnvironmentConfig{
Flags: map[string]shared.FlagConfig{
"new-checkout": {Key: "new-checkout", Type: "boolean", Enabled: true, Default: true},
},
},
})Toggle offline mode at runtime:
client.EnterOfflineMode() // Freeze flag values
client.ExitOfflineMode() // Resume streaming/pollingOperator Reference
String Operators
| Operator | Description | Example |
|---|---|---|
eq | Equals any value in list | country eq US, UK |
neq | Not equal to any value | plan neq free |
in | Is in list (alias for eq) | role in admin, editor |
contains | Contains substring | email contains @company |
does_not_contain | Does not contain | email does_not_contain test |
starts_with | Starts with prefix | email starts_with admin@ |
ends_with | Ends with suffix | email ends_with @company.com |
matches_regex | Matches regex | path matches_regex ^/api/v[0-9]+ |
Numeric Operators
| Operator | Description | Example |
|---|---|---|
gt | Greater than | age gt 18 |
gte | Greater than or equal | score gte 100 |
lt | Less than | error_rate lt 5 |
lte | Less than or equal | latency_ms lte 200 |
Semantic Version Operators
| Operator | Description | Example |
|---|---|---|
semver_eq | Version equals | app_version semver_eq 2.0.0 |
semver_gt | Greater than | app_version semver_gt 1.9.0 |
semver_gte | Greater than or equal | sdk_version semver_gte 3.0.0 |
semver_lt | Less than | app_version semver_lt 2.0.0 |
semver_lte | Less than or equal | app_version semver_lte 1.5.0 |
Date/Time Operators
| Operator | Description | Example |
|---|---|---|
before | Timestamp before value | created_at before 2026-01-01T00:00:00Z |
after | Timestamp after value | launch_time after 2026-04-01T00:00:00Z |
Values must be RFC 3339 format.
Segment Operator
| Operator | Description | Example |
|---|---|---|
segment_match | User is in the named segment | segment_match beta-testers |
Quick Reference Cheat Sheet
| Scenario | Flag Type | Key Setup |
|---|---|---|
| Kill switch | Boolean | Toggle flag on/off, no rules |
| Feature release | Boolean | Percentage rollout 0% → 100% |
| Canary release | Boolean | Gradual rollout schedule (1% → 5% → 25% → 100%) |
| A/B test (2 variants) | Boolean | 50/50 percentage rollout + experiment |
| A/B/n test (3+ variants) | String | Multi-variation percentage rollout + experiment |
| User opt-in | Boolean | Rule: key eq specific user IDs |
| Beta program | Boolean | Segment (list-based) + segment_match rule |
| Geo-targeting | Boolean | Rule: country eq target countries |
| Plan-gated feature | Boolean | Rule: plan eq pro, enterprise |
| Internal dogfooding | Boolean | Rule: email ends_with @company.com |
| Dynamic config | JSON | JSON flag with structured config object |
| Tunable parameter | Number | Number flag with named variations |
| Version gate | Boolean | Rule: app_version semver_gte minimum version |
| Scheduled launch | Boolean | Rule: launch_time after target datetime |
| Ring deployment | Boolean | Multiple segment rules in priority order |
| Feature dependency | Boolean | Prerequisites on parent flag |