Guards
A guard is a named control point in your code. Your application calls the guard by name at runtime and receives a boolean result that determines whether a code path should run. The guard's behavior is defined in Liteguard, not in your application code.
What a guard does
When your application calls isOpen('feature.name'), the Liteguard SDK evaluates the guard against the locally cached configuration bundle and returns true or false. There is no network call at evaluation time. The SDK fetches and refreshes the bundle in the background.
The result depends on three things, evaluated in this order:
- Rules — an ordered list of conditions on the properties you pass with the call. The first matching rule determines the result.
- Default value — if no rule matches, the guard returns its default value.
- Unadopted fallback — if Liteguard has not seen a configuration for this guard name yet, it returns
false.
Adopted and unadopted guards
A guard is unadopted when it has been observed by Liteguard (your code called isOpen with that name) but it does not yet have a configuration record in the project.
An unadopted guard always evaluates to false. It appears in the guard catalog on the Guards tab under a distinct section. Next to each unadopted guard is an Adopt button that lets you create a configuration record for it.
A guard is adopted when it has a configuration record in the project. Once adopted, the default value and rules you configure take effect immediately the next time the SDK refreshes its bundle.
Adopting a guard is how you transition from exploratory integration (just calling isOpen in your code) to deliberate rollout control (defining what the guard should do in each environment).
Default value
The default value is what isOpen returns when no rule matches. It is a boolean toggle on the guard's environment configuration.
- Default off (false) is the standard starting point for a new feature. The guard is closed for all callers that do not match a rule.
- Default on (true) is appropriate for a guard that should be open broadly, with rules applied only to exclude specific cases.
The default value is stored per environment. You can set a different default in staging than in production.
Rules
Rules let you evaluate the guard differently based on properties. Each rule has:
- Property name — the key in the properties map your code passes to
isOpen. - Operator — how to compare the property value. Available operators are
equals,not equals,in,not in,regex,>,>=,<, and<=. - Values — one or more values to compare against.
- Result — the boolean
isOpenreturns when this rule matches. - Enabled — whether this rule is currently active. Disabled rules are skipped during evaluation.
Rules are evaluated in the order they appear on the guard detail page. The first rule whose property name, operator, and values all match returns its result. If no rule matches, the default value applies.
Rule order matters. If two rules could match the same call, the one listed first wins.
Like the default value, rules are stored per environment.
Lifecycle
A guard's lifecycle state controls whether it is actively enforcing behavior.
- Active — the guard is enforcing its rules and default value normally.
- Archived — the guard configuration still exists but is treated as inactive. An archived guard evaluates to its last configured default value but the detail page shows it as not enforcing.
Use Active for any guard your application is currently relying on. Archive a guard when the feature it controlled has been fully released or permanently removed and you want to stop managing it without deleting its history.
The lifecycle state is a property of the guard record itself, not of the per-environment configuration. Archiving a guard affects all environments.
Measurement
By default, the SDK emits a telemetry signal for each isOpen call. Liteguard uses these signals to track evaluation counts and last-evaluated timestamps, which appear on the guard detail page and in the guard catalog list.
Measurement can be disabled on a per-environment basis if you want to reduce signal volume for a specific guard.
If you want to check a guard without emitting a telemetry signal, for example in a hot render loop, use peekIsOpen instead of isOpen. The result is the same but no signal is buffered.
Rate limiting
A guard can be configured with a per-minute rate limit. When a rate limit is set, isOpen returns false for calls that exceed the limit, regardless of rules or the default value.
Rate limits can be keyed to one or more property values. For example, a rate limit on userId applies the limit per unique user ID rather than as a global ceiling. When no rate limit properties are specified, the limit is global across all callers of that guard.
Rate limiting is configured per environment on the guard detail page.
Guard names
A guard's name is its usage key. It must match exactly between your code and the Liteguard UI. Guard names must start with an ASCII letter, may contain only ASCII letters, digits, ., -, _, and /, must be at least 3 characters long, and must not end with . or /. A common convention is a dot-separated path that groups related guards together, such as payments.checkout or api/v2/rate_limit. The name is case-sensitive.
Liteguard does not reject invalid names inside the client SDKs. The control plane enforces the contract server-side. In the TypeScript SDKs, string literals passed to guard APIs are checked at compile time.
Guard names are scoped to a project. The same name in two different projects refers to two independent guard configurations.
Guard catalog metrics
The Guards tab shows three summary metrics above the catalog:
- Adopted — the number of guards that have a configuration record, out of the total number that have been observed.
- Measuring — the number of adopted guards that are still emitting measurement signals, out of the total adopted count.
- Active — the number of adopted guards with an Active lifecycle state, out of the total adopted count.
These metrics reflect the state of the selected project and environment.