Flag Definitions
Flags
flags is a required property.
The flags property is a top-level property that contains a collection of individual flags and their corresponding flag configurations.
Flag Definition
flag key is a required property.
The flag key must uniquely identify a flag so it can be used during flag evaluation.
The flag key should convey the intent of the flag.
Flag properties
A fully configured flag may look like this.
{
"$schema": "https://flagd.dev/schema/v0/flags.json",
"flags": {
"new-welcome-banner": {
"state": "ENABLED",
"variants": {
"on": true,
"off": false
},
"defaultVariant": "off",
"targeting": {
"if": [
{ "ends_with": [{ "var": "email" }, "@example.com"] },
"on",
"off"
]
},
"metadata": {
"version": "17"
}
}
},
"metadata": {
"team": "user-experience",
"flagSetId": "ecommerce"
}
}
See below for a detailed description of each property.
State
state is a required property.
Validate states are "ENABLED" or "DISABLED".
When the state is set to "DISABLED", flagd will behave like the flag doesn't exist.
Example:
Variants
variants is a required property.
It is an object containing the possible variations supported by the flag.
All the values of the object must be the same type (e.g. boolean, numbers, string, JSON).
The type used as the variant value will correspond directly affects how the flag is accessed.
For example, to use a flag configured with boolean values the /flagd.evaluation.v1.Service/ResolveBoolean path should be used.
If another path, such as /flagd.evaluation.v1.Service/ResolveString is called, a type mismatch occurs and an error is returned.
Example:
Example:
Example of an invalid configuration:
Default Variant
defaultVariant is a required property.
The value must match the name of one of the variants defined above.
The default variant is always used unless a targeting rule explicitly overrides it.
Example:
Example:
Example of an invalid configuration:
Targeting Rules
targeting is an optional property.
A targeting rule must be valid JSON.
Flagd uses a modified version of JsonLogic, as well as some custom pre-processing, to evaluate these rules.
If no targeting rules are defined, the response reason will always be STATIC, this allows for the flag values to be cached, this behavior is described here.
Variants Returned From Targeting Rules
The output of the targeting rule must match the name of one of the defined variants.
One exception to the above is that rules may return true or false which will map to the variant indexed by the equivalent string ("true", "false").
If a null value is returned by the targeting rule, the defaultVariant is used.
This can be useful for conditionally "exiting" targeting rules and falling back to the default (in this case the returned reason will be DEFAULT).
If an invalid variant is returned (not a string, true, or false, or a string that is not in the set of variants) the evaluation is considered erroneous.
See Boolean Variant Shorthand.
Evaluation Context
Evaluation context provides the attributes used by targeting rules to determine flag values. Context can come from multiple sources, which are merged together before evaluation.
Context Sources
flagd supports three sources of evaluation context:
| Source | Flag | Description |
|---|---|---|
| Request body | - | Context sent with each evaluation request |
| Static context | -X / --context-value |
Key-value pairs added at startup, included in all evaluations |
| Header-mapped context | -H / --context-from-header |
Maps HTTP/gRPC request headers to context keys |
Request Body Context
Context included as part of the evaluation request. For example, when accessing flagd via HTTP, the POST body may look like this:
This is the most common approach when the calling application has user or session information available.
Static Context (-X flag)
Static context values are specified at startup and automatically included in every evaluation. This is useful for server-wide or environment-specific values that don't change per-request.
flagd start \
--uri file:./flags.json \
-X environment=production \
-X region=us-east-1 \
-X service=payment-api
Use cases:
- Environment identification: Different flag behavior for production vs staging (
-X environment=production) - Regional configuration: Apply region-specific rules (
-X region=eu-west-1) - Service identification: When multiple services share flag definitions (
-X service=checkout) - Infrastructure metadata: Cloud provider, datacenter, or cluster information
Header-Mapped Context (-H flag)
Header-mapped context extracts values from HTTP or gRPC request headers and adds them to the evaluation context. This enables context-sensitive evaluation without modifying request bodies.
With this configuration:
- A request with headers
X-User-Id: abc123andX-User-Tier: premiumwill haveuserId=abc123andtier=premiumin its evaluation context.
Use cases:
- Gateway integration: Extract user information from headers set by an API gateway or auth proxy
- Multi-tenancy: Use tenant ID headers for tenant-specific flag behavior
Context Merge Priority
When the same key appears in multiple context sources, values are merged with this priority (highest wins):
- Header-mapped context (
-Hflag) - highest priority - Static context (
-Xflag) - Request body context - lowest priority
For example, with this configuration:
| Request Body | Header | Resulting tier value |
|---|---|---|
{"context": {"tier": "free"}} |
(none) | basic (static overrides body) |
{"context": {"tier": "free"}} |
X-User-Tier: premium |
premium (header overrides all) |
| (none) | X-User-Tier: enterprise |
enterprise |
This priority order allows operators to enforce certain context values at the infrastructure level while still accepting client-provided context for other attributes.
Accessing Context in Targeting Rules
The evaluation context can be accessed in targeting rules using the var operation followed by the evaluation context property name.
| Description | Example |
|---|---|
| Retrieve property from the evaluation context | { "var": "email" } |
| Retrieve property from the evaluation context or use a default | { "var": ["email", "noreply@example.com"] } |
| Retrieve a nested property from the evaluation context | { "var": "user.email" } |
For more information, see the
varsection in the JsonLogic documentation.
See the cheat sheet for practical examples of context-sensitive evaluation.
Conditions
Conditions can be used to control the logical flow and grouping of targeting rules.
| Conditional | Example |
|---|---|
| If | Logic: {"if" : [ true, "yes", "no" ]}Result: "yes"Logic: {"if" : [ false, "yes", "no" ]}Result: "no" |
| If else | Logic: {"if" : [ false, "yes", false, "no", "maybe" ]}Result: "maybe"Logic: {"if" : [ false, "yes", false, "no", false, "maybe", "who knows" ]}Result: "who knows" |
| Or | Logic: {"or" : [ true, false ]}Result: trueLogic: {"or" : [ false, false ]}Result: false |
| And | Logic: {"and" : [ true, false ]}Result: falseLogic: {"and" : [ true, true ]}Result: true |
Operations
Operations are used to take action on or compare properties retrieved from the context. These are provided out-of-the-box by JsonLogic. It's worth noting that JsonLogic operators never throw exceptions or abnormally terminate due to invalid input. As long as a JsonLogic operator is structurally valid, it will return a falsy/nullish value.
| Operator | Description | Context attribute type | Example |
|---|---|---|---|
| Equals | Attribute equals the specified value, with type coercion. | any | Logic: { "==" : [1, 1] }Result: trueLogic: { "==" : [1, "1"] }Result: true |
| Strict equals | Attribute equals the specified value, with strict comparison. | any | Logic: { "===" : [1, 1] }Result: trueLogic: { "===" : [1, "1"] }Result: false |
| Not equals | Attribute doesn't equal the specified value, with type coercion. | any | Logic: { "!=" : [1, 2] }Result: trueLogic: { "!=" : [1, "1"] }Result: false |
| Strict not equal | Attribute doesn't equal the specified value, with strict comparison. | any | Logic: { "!==" : [1, 2] }Result: trueLogic: { "!==" : [1, "1"] }Result: true |
| Exists | Attribute is defined | any | Logic: { "!!": [ "mike" ] }Result: trueLogic: { "!!": [ "" ] }Result: false |
| Not exists | Attribute is not defined | any | Logic: {"!": [ "mike" ] }Result: falseLogic: {"!": [ "" ] }Result: true |
| Greater than | Attribute is greater than the specified value | number | Logic: { ">" : [2, 1] }Result: trueLogic: { ">" : [1, 2] }Result: false |
| Greater than or equals | Attribute is greater or equal to the specified value | number | Logic: { ">=" : [2, 1] }Result: trueLogic: { ">=" : [1, 1] }Result: true |
| Less than | Attribute is less than the specified value | number | Logic: { "<" : [1, 2] }Result: trueLogic: { "<" : [2, 1] }Result: false |
| Less than or equals | Attribute is less or equal to the specified value | number | Logic: { "<=" : [1, 1] }Result: trueLogic: { "<=" : [2, 1] }Result: false |
| Between | Attribute between the specified values | number | Logic: { "<" : [1, 5, 10]}Result: trueLogic: { "<" : [1, 11, 10] }Result: false |
| Between inclusive | Attribute between or equal to the specified values | number | Logic: {"<=" : [1, 1, 10] }Result: trueLogic: {"<=" : [1, 11, 10] }Result: false |
| Contains | Contains string | string | Logic: { "in": ["Spring", "Springfield"] }Result: trueLogic: { "in":["Illinois", "Springfield"] }Result: false |
| Not contains | Does not contain a string | string | Logic: { "!": { "in":["Spring", "Springfield"] } }Result: falseLogic: { "!": { "in":["Illinois", "Springfield"] } }Result: true |
| In | Attribute is in an array of strings | string | Logic: { "in" : [ "Mike", ["Bob", "Mike"]] }Result: trueLogic: { "in":["Todd", ["Bob", "Mike"]] }Result: false |
| Not in | Attribute is not in an array of strings | string | Logic: { "!": { "in" : [ "Mike", ["Bob", "Mike"]] } }Result: falseLogic: { "!": { "in":["Todd", ["Bob", "Mike"]] } }Result: true |
Custom Operations
These are custom operations specific to flagd and flagd providers. They are purpose-built extensions to JsonLogic in order to support common feature flag use cases. Consistent with built-in JsonLogic operators, flagd's custom operators return falsy/nullish values with invalid inputs.
| Function | Description | Context attribute type | Example |
|---|---|---|---|
fractional (available v0.6.4+) |
Deterministic, pseudorandom fractional distribution | string (bucketing value) | Logic: { "fractional" : [ { "var": "email" }, [ "red" , 50], [ "green" , 50 ] ] } Result: Pseudo randomly red or green based on the evaluation context property email.Additional documentation can be found here. |
starts_with |
Attribute starts with the specified value | string | Logic: { "starts_with" : [ "192.168.0.1", "192.168"] }Result: trueLogic: { "starts_with" : [ "10.0.0.1", "192.168"] }Result: falseAdditional documentation can be found here. |
ends_with |
Attribute ends with the specified value | string | Logic: { "ends_with" : [ "noreply@example.com", "@example.com"] }Result: trueLogic: { ends_with" : [ "noreply@example.com", "@test.com"] }Result: falseAdditional documentation can be found here. |
sem_ver |
Attribute matches a semantic versioning condition | string (valid semver) | Logic: {"sem_ver": ["1.1.2", ">=", "1.0.0"]}Result: trueAdditional documentation can be found here. |
Targeting key
flagd and flagd providers map the targeting key into the "targetingKey" property of the context used in rules.
For example, if the targeting key for a particular evaluation was set to "5c3d8535-f81a-4478-a6d3-afaa4d51199e", the following expression would evaluate to true:
$flagd properties in the evaluation context
Flagd adds the following properties to the evaluation context that can be used in the targeting rules.
| Property | Description | From version |
|---|---|---|
$flagd.flagKey |
the identifier for the flag being evaluated | v0.6.4 |
$flagd.timestamp |
a Unix timestamp (in seconds) of the time of evaluation | v0.6.7 |
Shared evaluators
$evaluators is an optional property.
It's a collection of shared targeting configurations used to reduce the number of duplicated targeting rules.
Example:
{
"$schema": "https://flagd.dev/schema/v0/flags.json",
"flags": {
"fibAlgo": {
"variants": {
"recursive": "recursive",
"memo": "memo",
"loop": "loop",
"binet": "binet"
},
"defaultVariant": "recursive",
"state": "ENABLED",
"targeting": {
"if": [
{
"$ref": "emailWithFaas"
},
"binet",
null
]
}
},
"headerColor": {
"variants": {
"red": "#FF0000",
"blue": "#0000FF",
"green": "#00FF00",
"yellow": "#FFFF00"
},
"defaultVariant": "red",
"state": "ENABLED",
"targeting": {
"if": [
{
"$ref": "emailWithFaas"
},
{
"fractional": [
{ "var": "email" },
["red", 25],
["blue", 25],
["green", 25],
["yellow", 25]
]
},
null
]
}
}
},
"$evaluators": {
"emailWithFaas": {
"in": [
"@faas.com",
{
"var": ["email"]
}
]
}
}
}
Metadata
Metadata can be defined at both the flag set (as a sibling of flags) and within each flag. Flag metadata conveys arbitrary information about the flag or flag set, such as a version number, or the business unit that is responsible for the flag. When flagd resolves flags, the returned flag metadata is a merged representation of the metadata defined in the flag set, and the metadata defined in the flag, with the metadata defined in the flag taking priority. See the playground for an interactive example.
Boolean Variant Shorthand
Since rules that return true or false map to the variant indexed by the equivalent string ("true", "false"), you can use shorthand for these cases.
For example, this:
{
"$schema": "https://flagd.dev/schema/v0/flags.json",
"flags": {
"new-welcome-banner": {
"state": "ENABLED",
"variants": {
"true": true,
"false": false
},
"defaultVariant": "false",
"targeting": {
"if": [
{ "ends_with": [{ "var": "email" }, "@example.com"] },
"true",
"false"
]
}
}
}
}
can be shortened to this:
{
"$schema": "https://flagd.dev/schema/v0/flags.json",
"flags": {
"new-welcome-banner": {
"state": "ENABLED",
"variants": {
"true": true,
"false": false
},
"defaultVariant": "false",
"targeting": {
"ends_with": [{ "var": "email" }, "@example.com"]
}
}
}
}
Examples
Sample configurations can be found at https://github.com/open-feature/flagd/tree/main/config/samples.