Skip to content

flagd basics

Your flagd journey will start by defining your feature flags.

flagd will then read those feature flags and make them available to your application.

Your application will interact with flagd via the OpenFeature SDK to retrieve flag values via the flagd API.

flagd architecture

Defining feature flags

Flags can be defined in either JSON or YAML syntax and the values can be of different types.

Here are two flags, flagOne has boolean values and flagTwo has string values.

flags represented as JSON

{
  "flags": {
    "flagOne": {
      "state": "ENABLED",
      "variants": {
        "on": true,
        "off": false
      },
      "defaultVariant": "on",
      "targeting": {}
    },
    "flagTwo": {
      "state": "ENABLED",
      "variants": {
        "key1": "val1",
        "key2": "val2"
      },
      "defaultVariant": "key1",
      "targeting": {}
    }
  }
}

flags represented as YAML

flags:
  flagOne:
    state: ENABLED
    variants:
      'on': true
      'off': false
    defaultVariant: 'on'
    targeting:
  flagTwo:
    state: ENABLED
    variants:
      key1: val1
      key2: val2
    defaultVariant: 'key1'
    targeting:

The structure of a flag

Each flag has:

  • A flag key: flagOne and flagTwo above
  • A state: ENABLED or DISABLED
  • One or more possible variants. These are the possible values that a flag key can take.
  • An optional targeting rule (explained below)

Targeting rules

Imagine you are introducing a new feature. You create a flag with two possible variants: on and off. You want to safely roll out the feature. Therefore the flags defaultValue is set to off for all users.

In other words, the new feature is disabled by default.

Now imagine you want to enable the feature, but only when the following is true:

  • Logged in users where the user's email ends in @example.com

Rather than codifying that in your application, flagd targeting rules can be used. The flag definition below models this behaviour.

When a user logs into your application, your application is responsible for sending the email address via OpenFeature's context parameter (see below) and flagd will return the correct flag. If the email address of the logged in users contains @example.com then flagd will return the on variant (ie. true). All other users receives the defaultVariant of off (ie. false). In this context, "all other users" means:

  • Any logged in user whos email does not contain @example.com
  • Any logged out user

Your application is responsible for sending the email address via OpenFeature's context parameter (see below) and flagd will return the correct flag.

{
    "flags": {
        "isFeatureEnabled": {
            "state": "ENABLED",
            "variants": {
                "on": true,
                "off": false
                },
            "defaultVariant": "off",
            "targeting": {
                "if": [{
                    "in": [
                        "@example.com",
                        {
                            "var": ["email"]
                        }]
                },
                "on", null]
            }
         }
    }
}

Pseudo-code of application passing context

// Here, we provide an empty context, hence the flag evaluates to false value which is the defaultVariant
featureAvailable = openFeature.getBooleanValue("isFeatureEnabled", false, {}) // false

// Here, we provide email for the flag evaluation. Still flag evaluates to defaultVariant of false as email does not end with desired domain
featureAvailable = openFeature.getBooleanValue("isFeatureEnabled", false, {"email": "example@gmail.com"}) // false

// Here, the flag is evaluated with targeting rule matching, hence the value of true
featureAvailable = openFeature.getBooleanValue("isFeatureEnabled", false, {"email": "someone@example.com"}) // true

Fractional Evaluation

In some scenarios, it is desirable to use contextual information to segment the user population further and thus return dynamic values.

Look at the headerColor flag below. The defaultVariant is red, but the flag contains a targeting rule, meaning a fractional evaluation occurs when a context is passed and a key of email contains the value @example.com.

In this case, 25% of the email addresses will receive red, 25% will receive blue, and so on.

{
    "flags": {
        "headerColor": {
            "variants": {
                "red": "#FF0000",
                "blue": "#0000FF",
                "green": "#00FF00",
                "yellow": "#FFFF00"
            },
            "defaultVariant": "red",
            "state": "ENABLED",
            "targeting": {
                "if": [{
                    "emailWithFaas": {
                        "in": ["@faas.com", {
                            "var": ["email"]
                            }]
                    }
                },
                {
                    "fractional": [
                        { "var": "email" },
                        [ "red", 25 ], [ "blue", 25 ], [ "green", 25 ], [ "yellow", 25 ]
                    ]
                }, null
                ]
            }
        }
    }
}

Fractional evaluations are sticky

Fractional evaluations are "sticky" (deterministic) meaning that the same email address will always belong to the same "bucket" and thus always receive the same color. This is true even if you run multiple flagd instances completely independently.

Note that the first argument to the fractional operator is an expression specifying the bucketing value. This value is used as input to the bucketing algorithm to ensure a deterministic result. This argument can be omitted, in which case a concatenation of the targetingKey and the flagKey will be used as the bucketing value.

See this page for more information on flagd fractional evaluation logic.

Migrating from legacy fractionalEvaluation

If you are using a legacy fractional evaluation (fractionalEvaluation), it's recommended you migrate to fractional. The new fractional evaluator supports nested properties and JsonLogic expressions. To migrate, simply use a JsonLogic variable declaration for the bucketing property, instead of a string:

old:

"fractionalEvaluation": [
    "email",
    [ "red", 25 ], [ "blue", 25 ], [ "green", 25 ], [ "yellow", 25 ]
]

new:

"fractional": [
    { "var": "email" },
    [ "red", 25 ], [ "blue", 25 ], [ "green", 25 ], [ "yellow", 25 ]
]

Other target specifiers

The example above shows the in keyword being used, but flagd is also compatible with:

flagd OpenTelemetry

flagd is fully compatible with OpenTelemetry:

  • flagd exposes metrics at http://localhost:8014/metrics
  • flagd can export metrics and traces to an OpenTelemetry collector.

See the flagd OpenTelemetry page for more information.