Lightweight feature flag server written in Go. Single binary, SQLite storage, zero external dependencies at runtime.
- Flag types — boolean, string, number, JSON
- Rule engine — conditions evaluated with AND logic, priority ordering, first match wins
- Segments — reusable groups of conditions shared across rules
- Rollout — percentage-based rollout with deterministic bucketing (MurmurHash3)
- 12 operators —
equals,not_equals,in,not_in,contains,starts_with,gt,gte,lt,lte,exists,regex - Nested context — dot-notation attribute resolution (
user.plan,user.meta.role) - API key auth — SHA-256 hashed keys with environment scoping (live/test/staging)
- SSE streaming — real-time flag change notifications
- Batch evaluation — evaluate multiple flags in a single request
- CLI — manage flags, segments, and evaluate from the terminal
docker run -d \
-p 8080:8080 \
-e FLAGGY_MASTER_KEY=$(openssl rand -hex 32) \
-v flaggy-data:/data \
-e FLAGGY_DB_PATH=/data/flaggy.db \
ghcr.io/alexis-marcel/flaggy:latestgit clone https://github.com/Alexis-Marcel/flaggy.git
cd flaggy
make build
FLAGGY_MASTER_KEY=my-secret-key ./bin/flaggyd| Variable | Default | Description |
|---|---|---|
FLAGGY_PORT |
:8080 |
Listen address |
FLAGGY_DB_PATH |
flaggy.db |
SQLite database path |
FLAGGY_MASTER_KEY |
(empty) | Master key for admin routes. If unset, auth is disabled (dev mode) |
All admin routes require Authorization: Bearer <MASTER_KEY>. Client routes (evaluate, stream) accept API keys or the master key.
POST /api/v1/flags Create a flag
GET /api/v1/flags List all flags
GET /api/v1/flags/{key} Get a flag
PUT /api/v1/flags/{key} Update a flag
DELETE /api/v1/flags/{key} Delete a flag
PATCH /api/v1/flags/{key}/toggle Toggle enabled/disabled
POST /api/v1/flags/{key}/rules Create a rule
PUT /api/v1/flags/{key}/rules/{ruleID} Update a rule
DELETE /api/v1/flags/{key}/rules/{ruleID} Delete a rule
POST /api/v1/segments Create a segment
GET /api/v1/segments List all segments
GET /api/v1/segments/{key} Get a segment
PUT /api/v1/segments/{key} Update a segment
DELETE /api/v1/segments/{key} Delete a segment
POST /api/v1/evaluate Evaluate a single flag
POST /api/v1/evaluate/batch Evaluate multiple flags
GET /api/v1/stream SSE stream of flag changes
export FLAGGY=http://localhost:8080
export AUTH="Authorization: Bearer my-secret-key"
# Create a flag
curl -s -H "$AUTH" $FLAGGY/api/v1/flags -d '{
"key": "new_checkout",
"type": "boolean",
"default_value": false,
"enabled": true
}'
# Create a segment for pro users
curl -s -H "$AUTH" $FLAGGY/api/v1/segments -d '{
"key": "pro_users",
"description": "Users on the pro plan",
"conditions": [{"attribute": "user.plan", "operator": "equals", "value": "\"pro\""}]
}'
# Create a rule that uses the segment
curl -s -H "$AUTH" $FLAGGY/api/v1/flags/new_checkout/rules -d '{
"description": "Enable for pro users",
"segment_keys": ["pro_users"],
"conditions": [],
"value": true,
"priority": 1
}'
# Evaluate
curl -s -H "$AUTH" $FLAGGY/api/v1/evaluate -d '{
"flag_key": "new_checkout",
"context": {"user": {"plan": "pro"}}
}'
# → {"flag_key":"new_checkout","value":true,"match":true,"reason":"rule_match"}# Connect to a server
export FLAGGY_SERVER=http://localhost:8080
flaggy flag list
flaggy flag create my_flag --type boolean --default false --enabled
flaggy flag enable my_flag
flaggy flag disable my_flag
flaggy segment list
flaggy segment create pro_users --description "Pro plan users" \
--conditions '[{"attribute":"user.plan","operator":"equals","value":"\"pro\""}]'
flaggy segment get pro_users
flaggy evaluate my_flag -c '{"user":{"plan":"pro"}}'- If the flag is disabled → return default value
- Sort rules by priority (lower number = higher priority)
- For each rule, evaluate all inline conditions AND all segment conditions (AND logic)
- First rule where everything matches → return the rule's value
- If a rule has a rollout percentage, hash
flagKey:entityIDto check if the user is in the bucket - No rule matched → return default value
Segments referenced by a rule that don't exist are treated as non-matching (fail closed).
MIT