Skip to content

Commit 340885b

Browse files
committed
Clarify managed variables docs
1 parent bf62cde commit 340885b

4 files changed

Lines changed: 25 additions & 24 deletions

File tree

docs/how-to-guides/client-side-feature-flags.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This guide shows how to set up a **JavaScript/TypeScript web application** using
66

77
## Prerequisites
88

9-
1. **Create your variables** in the Logfire UI (Settings > Variables) and mark them as **external** — see [External Variables and OFREP](../reference/advanced/managed-variables/external.md)
9+
1. **Create your variables** in the Logfire UI (**Runtime > Managed Variables**) and mark them as **External** — see [External Variables and OFREP](../reference/advanced/managed-variables/external.md)
1010
2. **Create an API key** with the `project:read_external_variables` scope — this restricted scope is safe to use in client-side code since it only exposes variables you've explicitly marked as external
1111

1212
## Installation

docs/reference/advanced/managed-variables/external.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ There are two fundamentally different ways to read managed variables, and the ch
88

99
### Pull-Based (Logfire SDK)
1010

11-
When you use `logfire.variable.get()` (or the `.get()` method on a variable created with `logfire.var()`), the SDK **pulls the full variable configuration** from the server and evaluates it locally:
11+
When you call `.get()` on a variable created with `logfire.var()`, the SDK **pulls the full variable configuration** from the server and evaluates it locally:
1212

1313
1. The SDK fetches all variable definitions, versions, labels, and rollout rules in a single request
1414
2. A background thread polls for updates (or listens via SSE)
@@ -26,7 +26,7 @@ The OFREP endpoints take a different approach — every evaluation is a **server
2626
2. The server evaluates the variable using the context and returns only the resolved value
2727
3. The client never sees the full configuration, other versions, or rollout rules
2828

29-
This is less efficient (one network request per evaluation or batch), but the full configuration is **never exposed** to the client. A client would have to brute-force individual keys to discover what variables exist.
29+
This is less efficient (one network request per evaluation or batch), but the full configuration is **never exposed** to the client. Single-flag evaluation returns only the requested variable's resolved value, while bulk evaluation returns resolved values for the variables the token is allowed to access.
3030

3131
**Requires:** `project:read_variables` or `project:read_external_variables` scope.
3232

@@ -46,7 +46,7 @@ By default, variables are **internal** — they are only accessible with an API
4646
| `project:write_variables` | Create, update, and delete variables and variable types |
4747

4848
!!! warning "API key scope and SDK access"
49-
An API key with only the `project:read_external_variables` scope **cannot be used with `logfire.variable.get()`** or any of the pull-based SDK variable methods. The SDK's pull-based approach requires `project:read_variables` because it fetches the full configuration. The `project:read_external_variables` scope only grants access to the OFREP evaluation endpoints.
49+
An API key with only the `project:read_external_variables` scope **cannot be used with `.get()` on variables created with `logfire.var()`** or any of the pull-based SDK variable methods. The SDK's pull-based approach requires `project:read_variables` because it fetches the full configuration. The `project:read_external_variables` scope only grants access to the OFREP evaluation endpoints.
5050

5151
### Setting a Variable as External
5252

@@ -103,7 +103,7 @@ POST /v1/ofrep/v1/evaluate/flags
103103

104104
- `targetingKey` is required and is used for deterministic rollout selection.
105105
- Any additional fields in `context` become attributes for conditional rules.
106-
- The OFREP response maps labels to the `variant` field for compatibility with OpenFeature clients.
106+
- The OFREP response maps the selected label or target to the `variant` field for compatibility with OpenFeature clients. For example, the variant can be a label such as `production`, the automatic `latest` target, or `null` when no remote value is resolved.
107107

108108
**Caching (bulk endpoint):**
109109

@@ -114,9 +114,9 @@ These endpoints require an API key with the `project:read_variables` or `project
114114

115115
### Response Behavior
116116

117-
When the server resolves a variable successfully, the OFREP response includes the resolved `value`, a `variant` (the label name), and `reason: "TARGETING_MATCH"`.
117+
When the server resolves a variable successfully, the OFREP response includes the resolved `value`, a `variant`, and a `reason` such as `"STATIC"`, `"SPLIT"`, or `"TARGETING_MATCH"`.
118118

119-
When no value can be resolved — either because the variable has no versions, or because no label matches the evaluation context (e.g., rollout weights sum to less than 1.0 and no latest version fallback exists) — the server returns:
119+
When no remote value can be resolved — for example, because the variable has no versions yet or routing selects **Code default** — the server returns:
120120

121121
```json
122122
{

docs/reference/advanced/managed-variables/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ And two labels pointing to those versions:
3939

4040
To roll out v3 to everyone, just move the `production` label from v2 to v3. To roll back, move it back to v2. No new versions need to be created — the label is just a pointer.
4141

42-
!!! tip "Code default fallback"
43-
If no labels are configured in the rollout, or if rollout weights sum to less than 1.0, the remaining traffic uses the **code default** (the `default` value passed to `logfire.var()`). To direct remaining traffic to the latest version instead, create a label that references `latest` and include it in your rollout.
42+
!!! tip "Latest and Code default"
43+
In the Logfire UI, every variable has an automatic `latest` entry that points to the most recently created version. New variables start by routing traffic to `latest`, but `latest` has no value until you create the first version. The **Targeting** tab also shows **Code default**, which is the `default` value passed to `logfire.var()` in your application.
4444

4545
!!! note "Code default as safety net"
46-
The `default` value you pass to `logfire.var()` serves as an always-available fallback hard-coded into your source code. If no versions have been created yet, or if the remote configuration is unreachable due to a networking issue, or if a remote value fails validation against your type, the SDK returns the code default instead of raising an error. This means your application always has a working value — the remote configuration improves it, but never breaks it.
46+
The `default` value you pass to `logfire.var()` serves as an always-available fallback hard-coded into your source code. If no remote value can be resolved, if the remote configuration is unreachable due to a networking issue, or if a remote value fails validation against your type, the SDK returns the code default instead of raising an error. This means your application always has a working value — the remote configuration improves it, but never breaks it.
4747

4848
## Structured Configuration
4949

docs/reference/advanced/managed-variables/ui.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Managing Variables in the Logfire UI
22

3-
The Logfire web UI provides a complete interface for managing your variables without any code changes. You can find it under **Settings > Variables** in your project. The page includes two tabs:
3+
The Logfire web UI provides a complete interface for managing your variables without any code changes. You can find it under **Runtime > Managed Variables** in your project. The page includes two tabs:
44

55
- **Variables**: browse, create, and manage your managed variables
66
- **Types**: define reusable JSON schemas for custom variable types
77

8-
Clicking a variable opens its **detail page**, which has four tabs: **Values**, **Targeting**, **History**, and **Settings**.
8+
Clicking a variable opens its **detail page**, which has **Values**, **Targeting**, **Optimize**, and **History** tabs. Users with write access also see **Settings**.
99

1010
![Variables list](../images/variables-list.png)
1111

@@ -31,26 +31,28 @@ For **Custom Types**, the schema is derived from the type and shown read-only; e
3131

3232
The **Values tab** is the primary interface for viewing and editing your variable's content. It combines label management with value editing in a single view.
3333

34-
The left sidebar shows all labels (both active and inactive), while the right panel displays the value for the selected label. Each label in the sidebar shows its name and what it points to (e.g., a version number, another label, or "latest").
34+
The left sidebar shows the automatic `latest` entry plus all labels (both active and inactive), while the right panel displays the value for the selected entry. Each label in the sidebar shows its name and what it points to (e.g., a version number, another label, `latest`, or **Code default**).
3535

36-
- Select a label in the sidebar to view its current value
36+
- Select `latest` or a label in the sidebar to view its current value
3737
- Click the **copy** button to copy the displayed value to your clipboard
3838
- Click the **compare** button to diff the selected label's value against another label — useful for reviewing differences between production and staging prompts, for example
39-
- Click **Edit** to modify the value, then **Save new version** to create a new version and assign it to the selected label
40-
- Click **Add label** to create new labels pointing to a specific version, another label, the latest version, or the code default
39+
- Click **Edit** to modify the value, then **Save new version** to create a new version. When `latest` is selected, the new version becomes the latest version. When a label is selected, the new version is assigned to that label.
40+
- Click **Add label** to create new labels pointing to a specific version, another label, `latest`, or **Code default**
4141

4242
![Variable detail values](../images/variable-detail-values.png)
4343

44-
**Labels** are mutable pointers to specific versions. They work like Docker tags or git branch names — you can move them to point at any version at any time.
44+
`latest` is always present and points to the most recently created version. A new variable has no versions yet, so `latest` has no value until you create the first version.
45+
46+
**Labels** are mutable pointers to specific versions or targets. They work like Docker tags or git branch names — you can move them to point at any version, another label, `latest`, or **Code default** at any time.
4547

4648
Common label patterns:
4749

4850
- **`production`** / **`staging`** / **`canary`**: Environment-based labels for gradual rollouts
4951
- **`control`** / **`treatment`**: A/B testing labels
5052
- **`stable`** / **`experimental`**: Risk-based labels
5153

52-
!!! note "No labels = code default"
53-
If a variable has no labels configured in its routing, your application serves the code default (the `default` value passed to `logfire.var()`). To serve the latest version instead, create a label that references `latest` and include it in your routing.
54+
!!! note "Code default"
55+
**Code default** is the `default` value passed to `logfire.var()` in your application. Use it when you want some traffic to ignore remote versions and keep using the value from code.
5456

5557
## Browsing Version History
5658

@@ -70,13 +72,12 @@ The **History tab** lets you browse all saved versions:
7072

7173
## Configuring Label Routing
7274

73-
The **Targeting tab > Default** section controls what percentage of requests receive each labeled version. The weights are entered as percentages (0100%) and must sum to 100% or less:
75+
The **Targeting tab > Default** section controls what percentage of requests receive each label, `latest`, or **Code default**. The editable weights are entered as percentages (0-100%) and must sum to 100% or less. **Code default** is the remaining percentage after label and `latest` weights are allocated.
7476

7577
- Set `production` to `90` and `canary` to `10` for a 10% canary deployment
7678
- Set `control` to `50` and `treatment` to `50` for a 50/50 A/B test
77-
- To send some traffic to the latest version, create a label that references `latest` and include it in the routing — for example, a `latest` label referencing latest at `10` and `control` at `50` sends 10% of traffic to the latest version, 50% to the control label, and the remaining 40% falls back to the code default
78-
- If weights sum to less than 100%, the remaining percentage uses the **code default**
79-
- If no labels are in the routing (empty), all traffic uses the code default
79+
- Set `latest` to `10` and `control` to `50` to send 10% of traffic to the most recently created version, 50% to the control label, and the remaining 40% to **Code default**
80+
- New variables start with `latest` at `100`, so all traffic uses the newest version once one exists
8081

8182
## Targeting with Conditional Rules
8283

@@ -100,4 +101,4 @@ For example, to give enterprise customers the production experience:
100101
![Variable detail targeting](../images/variable-detail-routing.png)
101102

102103
!!! important "Variable names must match"
103-
The variable name in the UI must exactly match the `name` parameter in your `logfire.var()` call. If they don't match, your application will use the code default instead of the remote configuration.
104+
The variable name in the UI must exactly match the `name` parameter in your `logfire.var()` call. If they don't match, your application will use **Code default** instead of the remote configuration.

0 commit comments

Comments
 (0)