Anatomy of rules¶
At the heart of FFS are rules. Each feature flag is backed by a rule. It boils down to functions as commonly known in programming, or formulas as commonly seen in spreadsheets. Functions accept data, and return a result. That is numeric, between 0
and 1
.
When it is 0
, the flag is disabled. When 1
, the flag is enabled. When in-between, the flag is partially enabled, meaning it is enabled for some users, proportionally to the value.
Examples¶
To build intuition, let's look at some examples:
0
: the flag is disabled.false
: the flag is disabled (same as0
).1
: the flag is enabled.true
: the flag is enabled (same as1
).0.5
: the flag is enabled for 50% of users.
Let's take it up a notch, and look at more useful rules:
gte(now(), datetime("2038-01-19T04:14:07+01:00"))
: enabled after January 19 2038 at 03:14:07 UTC.matches("*@example.com", env["user.email"])
: enabled for emails ending in@example.com
.map(now(), datetime("2022-11-08"), datetime("2022-11-15"), 0, 1)
: gradual rollout between November 8 and November 16, 2022.not(isblank(env["user.email"]))
: enabled for logged in users (assuming their email is set when logging in).pow(map(now(), datetime("2021-11-08"), datetime("2021-11-15"), 0, 1), 2)
: gradual rollout again, but exponential instead of linear over the week.
Environment¶
All metadata supplied by the SDK can be accessed using env["<key>"]
. You can send anything that makes sense to your app, and then use it in rules.
Info
Noticed env["user.email"]
in the examples above? It was supplied by the SDK.
Results¶
Results are always numerical. true
and false
are mapped to 1
and 0
, respectively. Any result that's neither a number nor boolean is treated as 0
.
Functions¶
Name | Type | Syntax | Description |
---|---|---|---|
isblank | Info | isblank(value) |
Checks if the value is blank. |
eq | Operator | eq(a, b) |
Checks if a is equal to b . |
gt | Operator | gt(a, b) |
Checks if a is greater than b . |
gte | Operator | gte(a, b) |
Checks if a is greater than or equal to b . |
lt | Operator | lt(a, b) |
Checks if a is less than b . |
lte | Operator | lte(a, b) |
Checks if a is less than or equal to b . |
now | Date | now() |
Returns the current date and time. |
datetime | Date | datetime(value) |
Returns a date and time. value must follow ISO-8601's format date and time, or date. |
matches | Lookup | matches(regex, value) |
Checks if value matches regex . |
contains | Lookup | contains(list, value) |
Checks if list contains value . |
not | Logical | not(value) |
Negates the result of value . |
and | Logical | and(a, b) |
Checks if both a and b are true. |
or | Logical | or(a, b) |
Checks if either a or b is true. |
if | Logical | if(condition, a, b) |
If condition is true, returns a . Otherwise, returns b . |
plus | Operator | plus(a, b) |
Adds a and b . |
minus | Operator | minus(a, b) |
Subtracts b from a . |
times | Operator | times(a, b) |
Multiplies a and b . |
div | Operator | div(a, b) |
Divides a by b . |
rem | Operator | rem(a, b) |
Returns the remainder of a divided by b . |
log | Math | log(a, b) |
Returns the logarithm of a to the base of b . |
ln | Math | ln(value) |
Returns the natural logarithm of value . |
pow | Math | pow(a, b) |
Returns a to the power of b . |
exp | Math | exp(value) |
Returns e to the power of value . |
map | Math | map(instart, inend, outstart, outend, value) |
Maps value over the range [instart, inend] and returns the result in the range [outstart, outend] . |