Featurevisor

Use cases

Scheduled releases

Deploy checkout with its launch time already configured, then enable it from that instant without another deployment, such as midnight on Black Friday. Featurevisor has no clock or scheduler: your application supplies the current time whenever it evaluates.

Declare the current time

Start with the default scaffold, which already declares userId. Add a timestamp attribute called now. This is an ordinary attribute name, not a reserved key:

attributes/now.yml
description: Current application time
type: string
format: date-time

Set the launch instant

Release at 2026-11-27T00:00:00Z. after is strict, so compare with one millisecond earlier to include the launch instant:

segments/afterCheckoutLaunch.yml
description: Checkout launch has arrived
conditions:
- attribute: now
operator: after
value: "2026-11-26T23:59:59.999Z"
description: Checkout launch has arrived
conditions: now after '2026-11-26T23:59:59.999Z'

An after operand of the launch instant itself would exclude that exact millisecond. Both operators take portable timestamps.

Z means UTC. For midnight in Amsterdam, one hour ahead of UTC in November, write the operand with that offset instead, '2026-11-26T23:59:59.999+01:00', and checkout launches at 23:00 UTC. Check daylight saving time for the date you choose.

End a sale

A sale that ends needs both bounds. Conditions in a list must all match, so this window opens at the launch instant and closes at the start of 1 December, running through Cyber Monday:

segments/blackFridaySale.yml
description: Black Friday sale window
conditions:
- attribute: now
operator: after
value: "2026-11-26T23:59:59.999Z"
- attribute: now
operator: before
value: "2026-12-01T00:00:00Z"
description: Black Friday sale window
conditions: |
now after '2026-11-26T23:59:59.999Z'
and now before '2026-12-01T00:00:00Z'

before is strict too, so the closing instant itself is outside the window. Use the segment in a rule as the next section does for afterCheckoutLaunch.

Do not use not around a date comparison as a substitute for the opposite operator. Missing or invalid dates make direct comparisons return false, which not may invert into a match.

Gate checkout

Replace the scaffold's checkout definition with this rule:

features/checkout.yml
description: Scheduled checkout release
bucketBy: userId
rules:
- key: launched
conditions: afterCheckoutLaunch
percentage: 100

Before launch, no rule matches and checkout is disabled. At launch, every user with a valid current timestamp gets it.

Users along time. Before 2026-11-27T00:00:00Z checkout is off, and from that instant it is on.

Refresh the context

Pass a fresh instant for each evaluation:

const context = {
userId: 'user-4',
now: new Date(),
}
const enabled = f.isEnabled('checkout', context)

An existing Date object does not advance with time. Replacing or refreshing the context is required, not only calling the getter again with an old value. Evaluate on each server request, on navigation or on an application timer.

React hooks are not driven by a clock and do not update because the launch time passes. Have your application refresh now in the context and trigger evaluation through its context update flow. The visible boundary depends on how often it does this.

Use a trusted server clock for access decisions or anything where timing matters. Users can change device clocks and browser context. Client evaluation controls presentation, not authorisation. Enforce protected operations on the server.

Test the boundary

Fix the time in test contexts instead of reading a real clock:

tests/features/checkout.spec.yml
feature: checkout
assertions:
- description: Off just before launch
at: 50
context:
userId: user-4
now: "2026-11-26T23:59:59.999Z"
expectedToBeEnabled: false
- description: On at launch
at: 50
context:
userId: user-4
now: "2026-11-27T00:00:00Z"
expectedToBeEnabled: true
- description: On after launch
at: 50
context:
userId: user-4
now: "2026-11-27T00:00:00.001Z"
expectedToBeEnabled: true
Commands
npx featurevisor lint
npx featurevisor test

Lint validates authoring and warns about malformed context. Test executes the assertions without a validation gate. To inspect the launch instant:

Command
npx featurevisor evaluate \
--feature=checkout \
--context='{"userId":"user-4","now":"2026-11-27T00:00:00Z"}' \
--explain

Deploy and roll back

Run lint and tests, then build and deploy the datafile before launch. Applications need to load that datafile and refresh their context, but no configuration change is needed at the launch instant.

Alternatively, merge and deploy a rule enabling checkout at launch time. That avoids clock based targeting, but the release then depends on CI, deployment and each application's datafile refresh. Choose that workflow when an operator must approve the moment.

To cancel the scheduled launch or roll it back, set the rule's percentage to 0, test and deploy the new datafile. The change takes effect when applications load it. Restoring a datafile that still contains the schedule will not disable checkout after its launch instant.

Previous
Decoupled releases