Advanced
Command Line Interface (CLI) Usage
Beyond just initializing a project and building datafiles, Featurevisor CLI can be used for a few more purposes.
Installation#
Use npx to initialize a project first:
$ mkdir my-featurevisor-project && cd my-featurevisor-project$ npx @featurevisor/cli initIf you wish to initialize a specific example as available in the monorepo:
$ npx @featurevisor/cli init --example=jsonAfter you have installed the dependencies in the project:
$ npm installYou can access the Featurevisor CLI from inside the project via:
$ npx featurevisorFeaturevisor finds featurevisor.config.js by walking up from the current directory. You can run commands from nested directories inside the project without changing back to its root.
To operate on another project, pass either form of the root directory option:
$ npx featurevisor build --rootDirectoryPath=../my-other-project$ npx featurevisor build --root-directory-path ../my-other-projectUse npx featurevisor <command> --help or npx featurevisor help <command> to see the available options for a command. Help remains available outside a project and when a project configuration cannot be loaded.
Built in commands reject unknown options and unexpected positional arguments. This helps catch spelling mistakes before a command does any work. Custom plugins can opt into the same validation by declaring their options.
Learn more in Quick start.
Linting#
Check if the definition files have any syntax or structural errors:
$ npx featurevisor lintUse --json for machine-readable output, and --json --pretty for prettified JSON output.
Learn more in Linting.
Building datafiles#
Generate JSON files, one per target and optional environment combination:
$ npx featurevisor buildPass --target=<target> one or more times to build only those targets. Without it, all targets are built.
In a project with sets, you can build a single set by passing --set:
$ npx featurevisor build --set=storefrontLearn more in Building datafiles.
Testing#
Test your features, segments, and global variables:
$ npx featurevisor testPass --target=<target> one or more times to build only those target datafiles and run untargeted assertions plus assertions for the selected targets. Segment tests are not filtered.
In a project with sets, you can test a single set by passing --set:
$ npx featurevisor test --set=storefrontLearn more in Testing.
Promote between sets#
In a project with sets, you can preview and apply promotions from one set to another.
Preview what would be copied:
$ npx featurevisor promote --from=dev --to=stagingApply the promotion to write destination files:
$ npx featurevisor promote --from=dev --to=staging --applyLearn more in Promotions.
Generate static catalog#
Build the catalog:
$ npx featurevisor catalog exportServe the built catalog (defaults to port 3000):
$ npx featurevisor catalog serveServe it in a specific port:
$ npx featurevisor catalog serve -p 3000Learn more in Catalog.
Generate code#
Generate TypeScript code from feature definitions:
$ npx featurevisor generate-code --language typescript --out-dir ./srcSee output in ./src directory. Pass repeatable --tag=<tag> or --target=<target> options to generate the union of features needed by several tags or targets.
Learn more in code generation page.
Find duplicate segments#
It is possible to end up with multiple segments having same conditions in larger projects. This is not a problem per se, but we should be aware of it.
We can find these duplicates early on by running:
$ npx featurevisor find-duplicate-segmentsIf we want to know the names of authors who worked on the duplicate segments, we can pass --authors:
$ npx featurevisor find-duplicate-segments --authorsFind usage#
Learn where entities are used and inspect the dependencies of a global variable.
Choose exactly one feature, segment, attribute, global variable, or unused entity query per command. Combining several queries is rejected so no selection is silently ignored.
For each of the find-usage commands below, you can optionally pass --authors to find who worked on the affected entities.
Segment usage#
$ npx featurevisor find-usage --segment=my_segmentAttribute usage#
$ npx featurevisor find-usage --attribute=my_attributeUnused segments#
$ npx featurevisor find-usage --unusedSegmentsUnused attributes#
$ npx featurevisor find-usage --unusedAttributesFeature usage#
$ npx featurevisor find-usage --feature=my_featureGlobal variable dependencies#
Shows the required features, segments, attributes, and reusable schema used by one global variable:
$ npx featurevisor find-usage --variable=supportEmailBenchmarking#
You can measure how fast or slow your SDK evaluations are for particular features.
The --n option is used to specify the number of iterations to run the benchmark for.
--n and the optional --inflate value must be positive integers. The --context value must be a JSON object. Invalid values are reported before the benchmark begins. --variation and --variable cannot be combined in one benchmark.
Pass --target=<target> one or more times to benchmark the same evaluation independently against each selected target datafile. Without it, the complete in-memory datafile is used.
The output includes both the total loop duration and individual evaluation timings:
Total duration: how long all benchmark iterations took togetherMinimum duration: fastest individual evaluationAverage duration: average individual evaluationMaximum duration: slowest individual evaluation
Use the individual evaluation timings when comparing SDK performance. The maximum value can include runtime pauses like garbage collection or process scheduling.
Feature#
To benchmark evaluating a feature itself if it is enabled or disabled via SDK's .isEnabled() method against provided context:
$ npx featurevisor benchmark \ --environment=production \ --feature=my_feature \ --context='{"userId": "123"}' \ --n=1000Variation#
To benchmark evaluating a feature's variation via SDKs's .getVariation() method:
$ npx featurevisor benchmark \ --environment=production \ --feature=my_feature \ --variation \ --context='{"userId": "123"}' \ --n=1000Variable#
To benchmark evaluating a feature's variable via the SDK's .getVariable() method:
$ npx featurevisor benchmark \ --environment=production \ --feature=my_feature \ --variable=my_variable_key \ --context='{"userId": "123"}' \ --n=1000To benchmark a global variable, omit --feature:
$ npx featurevisor benchmark \ --environment=production \ --variable=supportEmail \ --context='{"country": "nl"}' \ --n=1000Configuration#
To view the project configuration:
$ npx featurevisor configPrinting configuration as JSON:
$ npx featurevisor config --json --prettyEvaluate#
To learn why certain values (like feature and its variation or variables) are evaluated as they are against provided context:
$ npx featurevisor evaluate \ --environment=production \ --feature=my_feature \ --context='{"userId": "123", "country": "nl"}'This will show you full evaluation details helping you debug better in case of any confusion.
Pass --variable without --feature to inspect a global variable:
$ npx featurevisor evaluate \ --environment=production \ --variable=supportEmail \ --context='{"country": "nl"}'Pass --target=<target> one or more times to evaluate independently against the exact datafiles for those targets. With repeated targets and --json, the result is an array containing each target and its evaluations. A single target keeps the regular evaluation object shape.
It is similar to diagnostics in SDKs with debug level. But here instead, we are doing it at CLI directly in our Featurevisor project without having to involve our application(s).
If you wish to print the evaluation details in plain JSON, you can pass --json at the end:
$ npx featurevisor evaluate \ --environment=production \ --feature=my_feature \ --context='{"userId": "123", "country": "nl"}' \ --json \ --prettyThe --pretty flag is optional.
To print further logs in a more verbose way, you can pass --verbose:
$ npx featurevisor evaluate \ --environment=production \ --feature=my_feature \ --context='{"userId": "123", "country": "nl"}' \ --verboseExplaining a result#
Add --explain to describe why the SDK returned a value, using the evaluation details and local project definitions:
npx featurevisor evaluate \ --environment=production \ --feature=my_feature \ --context='{"userId":"123","country":"nl"}' \ --explainFor a global variable, use --variable instead:
npx featurevisor evaluate \ --environment=production \ --variable=campaignBanner \ --context='{"country":"nl","city":"amsterdam","device":"mobile"}' \ --explainThe terminal shows the value once, followed by a short explanation, the selected rule or override, and relevant selectors. Colours distinguish returned values, warnings, and errors. Supporting details are dimmed. Nested override paths and mutated field names appear as compact summaries. An absent value is distinguished from a returned null.
For nested global overrides, the explanation includes the authored override path and its value or mutation declarations. Mutations are resolved during datafile building. The SDK selects a complete value; it does not apply these mutations during evaluation. Feature variable results identify their selected source where available, but do not include an authored mutation history.
This is an explanation of the outcome, not a complete execution trace. It does not rerun conditions or dependencies, invent reasons for rejected overrides, or claim that every declared requirement was checked. Use --explain --json for full evidence, authored value declarations, repeated diagnostic observations, and limitations. The JSON evidence is labelled as an SDK result, an SDK diagnostic, or definition information.
Evaluation uses a datafile built from your current local project. It does not fetch your deployed datafile, and it does not update allocation state files. The explanation identifies the selected environment, set, and Target. If an entity exists locally but is absent from that datafile, check its Target selection, exposure, and archiving settings.
Structured explanations#
Combine --explain --json --pretty to add an explanation property alongside the existing evaluation fields. Without --explain, the JSON format is unchanged.
- For a feature,
explanationcontainsflag,variation, andvariablesentries. - For a global variable,
explanationdescribes that variable directly. - With repeated Targets, each array entry retains its
targetandevaluationsfields. The explanation lives insideevaluations.explanation.
Each explanation has version: 1, mode: "outcome", source, result, summary, evidence, and limitations. result.hasValue is false when no value was returned, and the value field is then omitted. A returned null has hasValue: true and value: null.
Before printing an explanation, the CLI checks its recorded result and selected value sources against the SDK output. A contradiction stops the command with exit code 1 and an error message. JSON errors use evaluation_explanation_mismatch and list the conflicting fields in details.mismatches. Missing diagnostic information is a limitation, not a mismatch. These checks do not rerun selectors or prove every intermediate step.
Use --verbose for additional raw diagnostics in terminal output. It does not add diagnostic logs to JSON output. Explanations can contain configuration values and selector details, so review them before sharing.
Comparing changes#
Review changes to your Featurevisor definitions in a readable form:
$ npx featurevisor diffThe comparison is selected automatically:
- With uncommitted changes, compare the last commit on the current branch with the working tree. This takes precedence on every branch, including the primary branch.
- On a clean primary branch, such as
mainormaster, there are no changes to show. - On another clean branch, compare the primary branch with the current commit.
Staged changes, unstaged changes, deleted files, and untracked definitions are included. Ignored untracked files are excluded. The comparison uses the final files on disk, not an intermediate staged version. Changes anywhere in the Git working tree select the uncommitted comparison, but only the current Featurevisor project's definitions are reported.
Choose Git references explicitly to override these defaults:
$ npx featurevisor diff --from=main --to=HEAD$ npx featurevisor diff --from=v3.9.0 --to=v3.10.0$ npx featurevisor diff --from=HEAD --to=working-treeReferences can be branches, tags, or commit hashes. working-tree is a reserved endpoint name for the current files on disk. Passing only --from compares that reference with the working tree. Passing only --to compares HEAD with that reference. Commit comparisons use the two commit contents directly, not their merge base.
For example, a changed global variable appears as:
Comparing HEAD → working-tree~ variable supportEmail Default value: "[email protected]" → "[email protected]"0 added, 1 changed, 0 removedThe report covers features, global variables, segments, attributes, groups, schemas, targets, and test specifications. It ignores comments, formatting, and object property order.
Rules and overrides are matched by their keys, and variations by their values. Inserting a rule does not make every subsequent rule appear updated. The terminal report names each added, updated, or removed item within its environment and parent:
~ feature showBanner Rules ("production") Rule "rollout" updated Rollout percentage: 10 → 50Nested global overrides retain their parent hierarchy. Feature variable overrides are grouped under their rule or variation and variable key. A change in the relative order of existing rules or overrides is reported separately, because order affects evaluation. Added items show their new position, starting at one. Lists with missing or duplicate identities are explicitly compared by position instead. Arbitrary arrays inside variable values remain ordinary values, even if their objects have a key property.
A renamed definition, rule key, or override key appears as a removal and an addition.
In projects using sets, all sets present in either version are compared. Use --set to select one:
$ npx featurevisor diff --set=production$ npx featurevisor diff --from=main --to=HEAD --json --prettyJSON output contains from, to, the selection reason, warnings, a summary, and entity changes. Each entity includes its key, type, file, optional set, positional field changes with before and after values, and readable details grouped by authored identities. Field changes retain JSON Pointer syntax with array positions starting at zero; readable details use positions starting at one. A successful comparison exits with status 0, whether or not it finds changes. Invalid references, unreadable definitions, and unresolved working tree conflicts exit with status 1.
The command reads local Git history without fetching, checking out files, building datafiles, or changing build state. Primary branch discovery uses the upstream or remote default branch when known, then local main, master, or the configured Git default branch, with remote main or master as a fallback. An existing local primary branch takes precedence over its remote tracking version. Update your local Git references yourself when you want a newer baseline, or pass explicit references.
This is a comparison of authored definitions, not a prediction of which users will receive different evaluations. Both versions use the current project's parser and directory configuration. Changes to featurevisor.config.js are reported, with a warning when the compared configuration differs from the current configuration. Historical configuration is not executed. Review configuration changes and directory moves with git diff, since files outside the current directory layout cannot be classified. The filesystem datasource adapter and an existing Git commit are required.
List#
Choose exactly one entity type for every list command. Featurevisor reports an error if none or more than one are selected. Archived features, segments, attributes, and global variables are hidden by default. Pass --archived=true to list archived definitions, or --archived=false to request active definitions explicitly.
List datafiles#
To list generated datafiles in the configured datafiles/ directory:
$ npx featurevisor list --datafilesThe result is a three-column table of paths relative to datafiles/, their uncompressed sizes, and their gzip-compressed sizes, excluding the REVISION file and hidden files. Size values are right-aligned and always show two decimal places; one-character B suffixes are padded to align with kB and mB. There is an empty line between directories. Directories beginning with dev appear first and those beginning with prod appear last. Sizes use coloured B, kB, and mB suffixes in terminal output. With --json, each item has path, byte size, and byte gzipSize fields in the same order.
| Option | Description |
|---|---|
--json | print as JSON |
--pretty | pretty JSON |
List features#
To list all features in the project:
$ npx featurevisor list --featuresAdvanced search options:
| Option | Description |
|---|---|
--archived=<true or false> | by archived status |
--description=<pattern> | by description pattern |
--disabledIn=<environment> | disabled in an environment |
--enabledIn=<environment> | enabled in an environment |
--json | print as JSON |
--keyPattern=<pattern> | by key pattern |
--promotable=<true or false> | by promotion eligibility |
--tag=<tag> | by tag |
--target=<target> | selected by one or more repeatable targets |
--variable=<variableKey> | containing specific variable key |
--variation=<variationValue> | containing specific variation key |
--with-tests | with test specs |
--with-variables | with variables |
--with-variations | with variations |
--without-tests | without any test specs |
--without-variables | without any variables |
--without-variations | without any variations |
List segments#
To list all segments in the project:
$ npx featurevisor list --segmentsAdvanced search options:
| Option | Description |
|---|---|
--archived=<true or false> | by archived status |
--description=<pattern> | by description pattern |
--json | print as JSON |
--keyPattern=<pattern> | by key pattern |
--pretty | pretty JSON |
--promotable=<true or false> | by promotion eligibility |
--with-tests | with test specs |
--without-tests | without any test specs |
List global variables#
To list independently defined variables:
$ npx featurevisor list --variablesAdvanced search options:
| Option | Description |
|---|---|
--archived=<true or false> | by archived status |
--description=<pattern> | by description pattern |
--json | print as JSON |
--keyPattern=<pattern> | by key pattern |
--pretty | pretty JSON |
--promotable=<true or false> | by promotion eligibility |
--tag=<tag> | by one or more repeatable tags |
--target=<target> | selected by one or more repeatable targets |
--with-tests | with test specs |
--without-tests | without any test specs |
List attributes#
To list all attributes in the project:
$ npx featurevisor list --attributesAdvanced search options:
| Option | Description |
|---|---|
--archived=<true or false> | by archived status |
--description=<pattern> | by description pattern |
--json | print as JSON |
--keyPattern=<pattern> | by key pattern |
--pretty | pretty JSON |
--promotable=<true or false> | by promotion eligibility |
List groups#
To list exclusion groups:
$ npx featurevisor list --groupsGroups support --description, --keyPattern, --promotable, --json, and --pretty filters and output options.
List schemas#
To list reusable schemas:
$ npx featurevisor list --schemasSchemas support --description, --keyPattern, --promotable, --json, and --pretty filters and output options.
List targets#
To list targets:
$ npx featurevisor list --targetsTargets support --description, --keyPattern, --promotable, --json, and --pretty filters and output options.
List tests#
To list all tests specs in the project:
$ npx featurevisor list --testsAdvanced search options:
| Option | Description |
|---|---|
--applyMatrix | expand matrices into final assertions |
--assertionPattern=<pattern> | by assertion's description pattern |
--entityType=<type> | only feature, segment, or variable specs |
--json | print as JSON |
--keyPattern=<pattern> | by key pattern of feature or segment being tested |
--pretty | pretty JSON |
--promotable=<true or false> | by promotion eligibility of the test spec |
Assess distribution#
To check if the gradual rollout of a feature and the weight distribution of its variations (if any exists) are going to work as expected in a real world application with real traffic against provided context, we can imitate that by running:
$ npx featurevisor assess-distribution \ --environment=production \ --feature=my_feature \ --context='{"country": "nl"}' \ --populateUuid=userId \ --n=1000The --n option controls the number of iterations to run, and the --populateUuid option is used to simulate different users in each iteration in this particular case.
The iteration count must be a positive integer, and --context must contain a JSON object.
Further details about all the options:
--environment: the environment name--feature: the feature key--context: the common context object in stringified form--populateUuid: attribute key that should be populated with a new UUID, and merged with provided context.- You can pass multiple attributes in your command:
--populateUuid=userId --populateUuid=deviceId
- You can pass multiple attributes in your command:
--n: the number of iterations to run the assessment for- The higher the number, the more accurate the distribution will be
--target: assess the exact target datafile; repeat it to assess several targets independently--verbose: print the merged context for better debugging
Everything is happening locally in memory without modifying any content anywhere. This command exists only to add to our confidence if questions arise about how effective traffic distribution in Featurevisor is.
Info#
Shows counts for attributes, segments, features, variables, groups, schemas, targets, test specs, and expanded test assertions in the project:
$ npx featurevisor infoPass --target=<target> one or more times to show counts and datafile sizes for each selected target in each environment. Without it, info shows the project-wide entity counts.
Error output#
When a command fails, Featurevisor prints the message to standard error and exits with a non-zero code.
If --json is passed, the failure is printed as a structured object instead, which is easier to handle in scripts and CI:
{ "error": { "code": "unknown_command", "message": "Unknown command \"frobnicate\".", "details": { "command": "frobnicate" } }}The code property is stable and meant to be matched against, while message is written for humans. The details object carries additional context when there is any, and is an empty object otherwise. Add --pretty to indent the output.
Codes you are most likely to encounter are invalid_cli_arguments for a misspelled option or an unexpected positional argument, unknown_command for a command that does not exist, project_not_found when no featurevisor.config.js could be found, and invalid_project_configuration when the configuration file could not be loaded.
Version#
Get the current version number of Featurevisor CLI, and its relevant packages:
$ npx featurevisor versionOr do:
$ npx featurevisor --versionOr do:
$ npx featurevisor -v
