Featurevisor

Define your configuration

Segments

Segments are named, reusable conditions on attributes, segments, features and variables. Feature rules, force entries and variable overrides refer to them by key, so an audience such as the Netherlands is defined once.

Create a segment

Each segment is a YAML file in segments/. The file name is its key. The project that init creates already declares netherlands:

segments/netherlands.yml
description: The Netherlands
conditions:
- attribute: country
operator: equals
value: nl

It matches any context whose country is nl. Both description and conditions are required. To group keys in directories, see Namespaces.

Refer to the segment by its key:

features/checkout.yml
description: Checkout redesign
bucketBy: userId
rules:
- key: netherlands
conditions: netherlands
percentage: 100
- key: everyone
conditions: '*'
percentage: 25

'*' matches every context, so you do not need a segment for everyone. Rules can also combine segment keys with and, or and not, as Features shows. Variable overrides and force entries take segments the same way.

Name each segment after the audience your team talks about, such as payingAccounts or largeAccounts, so a rule reads like the release plan behind it. A change to a segment reaches every feature and variable that refers to it. That makes the segment the one place to update an audience, and a change to review with care. Check what depends on it first with find usage.

Write conditions

An attribute leaf compares one value in the context:

PropertyDescription
attributeAn attribute key. For an object attribute, a dotted path such as account.seats selects a property.
operatorHow to compare. The operator reference lists each one with the types it accepts.
valueWhat to compare against, of the attribute's type. Omit it for exists, notExists, isNull, notNull, empty and notEmpty.
regexFlagsOptional flags for matches and notMatches, such as i to ignore case.

These segments use the plan and account attributes declared in Attributes:

segments/payingAccounts.yml
description: Paid and enterprise accounts
conditions:
- attribute: plan
operator: in
value:
- paid
- enterprise
segments/largeAccounts.yml
description: Accounts with 50+ seats
conditions:
- attribute: account.seats
operator: greaterThanOrEquals
value: 50

Linting checks every value against the attribute's declaration, so piad fails where plan only allows free, paid and enterprise. In attribute conditions, in and notIn only work with string attributes. For numbers, combine equals conditions with or.

Combine conditions

A list under conditions matches when every condition in it matches. Group conditions with and, or and not to say more:

GroupMatches when
andEvery condition in it matches
orAt least one condition in it matches
notThe conditions in it do not all match

Groups nest. This segment matches Dutch accounts that are on enterprise or have 50 or more seats:

segments/prioritySupport.yml
description: Dutch enterprise or 50+ seats
conditions:
- attribute: country
operator: equals
value: nl
- or:
- attribute: plan
operator: equals
value: enterprise
- attribute: account.seats
operator: greaterThanOrEquals
value: 50

Exclude with not

The conditions inside not are combined with and before the result is negated. So this matches everyone except Dutch enterprise accounts. A Dutch account on free still matches, and so does a German enterprise account:

segments/notDutchEnterprise.yml
# ...
conditions:
not:
- attribute: country
operator: equals
value: nl
- attribute: plan
operator: equals
value: enterprise

To exclude every context that matches either condition, put an or group inside not:

segments/notDutchNorEnterprise.yml
# ...
conditions:
not:
- or:
- attribute: country
operator: equals
value: nl
- attribute: plan
operator: equals
value: enterprise

Each group needs at least one condition. Empty arrays and groups are lint errors and return false at runtime. Write conditions: '*' to match every context. The wildcard is valid only as the whole expression.

Reference other definitions

Segments accept the same four leaf kinds as every other selector. Reuse netherlands, require live chat and compare maintenance mode:

segments/chatSupport.yml
description: Dutch chat outside maintenance
conditions:
- netherlands
- feature: liveChat
- variable: maintenanceMode
operator: equals
value: false

A feature variable leaf adds feature to variable. Mix these leaves inside and, or and not too. Lint rejects direct and indirect cycles, including a feature rule that reaches its own flag through a segment. Runtime segment cycles fail the whole evaluation with error.

Test a segment

A segment spec states which contexts should match. Write one for every segment with more than a single condition:

tests/segments/prioritySupport.spec.yml
segment: prioritySupport
assertions:
- description: Dutch enterprise account
context:
country: nl
plan: enterprise
expectedToMatch: true
- description: Large Dutch account
context:
country: nl
plan: paid
account:
locale: nl-NL
seats: 80
expectedToMatch: true
- description: German enterprise account
context:
country: de
plan: enterprise
expectedToMatch: false
Command
npx featurevisor test --entity-type=segment

When a segment depends on a feature or variable, directly or through another segment, add environment to each assertion if the project configures environments. Optional at controls dependency bucketing, while stickyFeatures and stickyVariables pin dependency results. Segment checks inside other specs inherit those settings from their enclosing assertion. Attribute only segments do not need an environment.

Each assertion covers one branch: the enterprise plan, the seat count, and a country outside the Netherlands. See Testing for checks across several entities.

Datafiles

A datafile includes a segment only when a feature or global variable in its target uses it, in a rule, a force entry or an override. The SDK evaluates them while it resolves those features and variables.

Find usage and duplicates

Before changing a segment, see what depends on it. The CLI lists the features, global variables and other segments that use a segment, the segments nothing uses, and segments with identical conditions:

Commands
npx featurevisor find-usage --segment=netherlands
npx featurevisor find-usage --unused-segments
npx featurevisor find-duplicate-segments

Archiving

Set archived: true on a segment you no longer use:

segments/largeAccounts.yml
archived: true
description: Accounts with 50+ seats
conditions:
- attribute: account.seats
operator: greaterThanOrEquals
value: 50

An archived segment is left out of every datafile, where a reference to it would never match, and not around it would match everyone. Linting stops an active feature, global variable, segment or spec from still referring to it. Remove its references first, using find-usage above.

Lint checks an archived segment for its shape only, without resolving the attributes and definitions its conditions name. Keep the file rather than deleting it, so the key is not reused with another meaning. You can list archived segments afterwards:

Command
npx featurevisor list --segments --archived

Promotable

In a project that uses sets, a segment can protect its existing destination definition from later promotions by setting promotable: false at the top level:

sets/production/segments/netherlands.yml
description: The Netherlands
promotable: false
conditions:
- attribute: country
operator: equals
value: nl

If the destination segment exists, it remains unchanged when either the source or destination segment has this field. A missing destination segment is still created and retains promotable: false. Individual conditions cannot be protected separately.

Previous
Attributes