# Manage feature flags

**URL:** https://heroiclabs.com/docs/satori/concepts/remote-configuration/manage-feature-flags/
**Summary:** Create, update, and delete feature flags in the Satori console, manage their variants, and fetch resolved flag values from your game client or Nakama server runtime.
**Keywords:** create feature flag, edit feature flag, delete feature flag, flag variants, fetch feature flags, GetFlagsAsync, GetFlagAsync, GetFlagOverridesAsync, flag schema, category labels, inspect player flags
**Categories:** satori, remote-configuration

---


# Manage feature flags

This page covers the operations available for working with flags day to day. For the concepts behind flags, variants, and the override hierarchy, see [Understand feature flags](/satori/concepts/remote-configuration/understand-feature-flags/).

## Create a feature flag

In the Satori console, go to **Feature Flags** and select **New Feature Flag**.

Provide the following:

- **Name**: A unique identifier for the flag. Names must start with a letter, can contain letters, digits, dots, underscores, and hyphens, and must end with a letter or digit. Maximum 64 characters.
- **Description** (optional): A short note describing the flag's purpose. Maximum 128 characters.
- **Category labels** (optional): Assign one or more category labels to organise and filter flags in both the console and the client API.
- **Value**: The default value all players receive. This can be a string, number, boolean, or JSON object up to 128 KB. If you select a schema, the value is validated against it on save.
- **Schema** (optional): Choose a schema to enforce type validation on the flag's value and all its variant values. Satori provides built-in schemas for common types (String, Number, Boolean, Object, and others). Leave as "ANY" to skip validation.
  - To create new schemas, go to **Taxonomy → Schema Validators** and select **Create new schema**.
  - If you have an active Hiro license, additional schema options are shown. Select one to pre-populate the value field with Hiro-specific placeholders. You may need to toggle on **Form view** to see these fields.

{{< screenshot src="images/create-feature-flag.png" alt="Creating a feature flag through the form editor in the Satori console" caption="A custom schema is used to create this feature flag" width="80%" >}}

## Edit a feature flag

Select a flag from the **Feature Flags** list to open its detail page. Select **Edit default** to update the flag's value, description, schema, or category labels.

Changes to a flag's value propagate to all server instances in real time via cache invalidation. Players receive the updated value on their next configuration fetch.

{{< note "important" >}}
Flags marked as Hiro flags, such as Hiro-Stats, can only have their value and description updated. The name, schema, and other fields are locked.
{{< /note >}}

## Delete a feature flag

Open the flag's detail page and select **Delete**.

Two constraints apply: Hiro flags can't be deleted, and flags referenced by a running or future experiment phase can't be deleted. Satori surfaces these constraints before confirming deletion. Deleting a flag also removes all its variants.

## Create and manage variants

From a flag's detail page, select **Create Variant** to add an audience-targeted variant.

Provide the following:

- **Name**: A unique name within this flag. Same naming rules as flag names.
- **Value**: The variant-specific value. Validated against the flag's schema if one is set.
- **Audiences**: Select one or more audiences to target. At least one audience is required, and the special "ALL" audience can't be used for variants.

When a variant is selected, differences between its value and the default value are highlighted.

When more than one variant exists, each is assigned a position that determines its priority relative to other variants on the same flag. If a player qualifies for multiple variants, the top-most position wins. Reorder variants at any time by dragging the handle on the flag's detail page.

{{< screenshot src="images/feature-flag-variants.png" alt="A screenshot from the Satori console displays an AdsConfig feature flag that has three variants. The differences between the variant and the default flag are highlighted in the main view." caption="This feature flag has three variants, which can be re-ordered by dragging them in the UI. The differences between the variant and the default are highlighted in the main view." width="100%" >}}

To update a variant, select it from the flag's detail page and edit its name, value, audiences, or position. To delete a variant, select it and choose **Delete**. Remaining variants are automatically repositioned.

## Fetch flags from the game client

The Satori client SDK retrieves a player's resolved flag values after authentication. The SDK returns the final resolved value for each flag based on the player's audiences, active experiments, and live events.

This section reviews the available methods for fetching flags client-side. See [Client libraries](../../../client-libraries/) for more informat∂ion.

### Get all flags

```csharp
var flags = await client.GetFlagsAsync(session, null);
foreach (var flag in flags)
{
    Debug.LogFormat("{0}: {1}", flag.Name, flag.Value);
}
```

```json
{
  "flags": [
    {
      "name": "Allowed-Loot-Boxes",
      "value": "3"
    }
  ]
}
```

#### Understand `change_reason`

When a flag's value differs from its default, the response includes a `change_reason` field that tells you what changed it.

```json
{
  "flags": [
    {
      "name": "Allowed-Loot-Boxes",
      "value": "4",
      "condition_changed": true,
      "change_reason": {
        "type": 3,
        "name": "Loot-Box-Effect-on-LTV",
        "variant_name": "Loot-Box-Effect-on-LTV:Variant-A---More-Loot-Boxes"
      }
    }
  ]
}
```

The `change_reason` field contains three properties:

| Property       | Description                                                |
| -------------- | ---------------------------------------------------------- |
| `type`         | The source of the change. See table below.                 |
| `name`         | The name of the Satori feature responsible for the change. |
| `variant_name` | The specific variant within that feature, if applicable.   |

| Change reason type | Source              |
| ------------------ | ------------------- |
| (none)             | Flag default value  |
| `1`                | Flag variant        |
| `2`                | Live event override |
| `3`                | Experiment override |

### Get specific flags by name

```csharp
var flags = await client.GetFlagsAsync(session, "storeConfig", "eventScoring");
```

### Get a single flag with a safe default

Specify a fallback value so the call returns a usable result even when the network is unavailable, rather than throwing an exception.

```csharp
var flag = await client.GetFlagAsync(session, "storeConfig", "{}");
```

### Get flag overrides

To see every configuration source affecting a player's flags, not just the resolved value, use `GetFlagOverridesAsync`. This returns the full override chain: the flag default, any matching variants, active live event overrides, and experiment overrides.

```csharp
var overrides = await client.GetFlagOverridesAsync(session);
```

Each entry in the response carries a `type` field indicating its source:

| Override type | Source                  |
| ------------- | ----------------------- |
| (none)        | Flag default value      |
| `1`           | Flag variant            |
| `2`           | Live event override     |
| `3`           | Live event flag variant |
| `4`           | Experiment override     |

Example response (trimmed):

```json
{
  "flags": [
    {
      "flag_name": "Allowed-Loot-Boxes",
      "overrides": [
        {
          "name": "Allowed-Loot-Boxes",
          "value": "3"
        },
        {
          "type": 1,
          "name": "Allowed-Loot-Boxes",
          "variant_name": "New-Users-Have-5-LootBoxes-Variant",
          "value": "5"
        },
        {
          "type": 2,
          "name": "Christmas-Tournament",
          "value": "6",
          "create_time_sec": "1740066612"
        },
        {
          "type": 4,
          "name": "Loot-Box-Effect-on-LTV",
          "variant_name": "Loot-Box-Effect-on-LTV:Variant-A---More-Loot-Boxes",
          "value": "4",
          "create_time_sec": "1739789141"
        }
      ]
    }
  ]
}
```

This is the programmatic equivalent of the override inspector in the console. Use it for debugging, logging which override source is active for a player, or building client-side UI that adapts based on override context. It's also possible to manually select from this list which flag value to serve to the player.

{{< note "important" >}}
Using alternative values from this endpoint won't change which live event or experiment the player has joined. Metrics, live event, and experiment results in the Satori console aren't aware of the value you choose to show to your player.
{{< /note >}}

### Filter by category label

Both `GetFlagsAsync` and `GetFlagOverridesAsync` support filtering by category labels, so you can request only the flags relevant to a specific system — for example, all flags labelled `economy`. See [Category labels](../../category-labels/).

## Fetch flags from the Nakama server runtime

If your game server needs to read a player's flags server-side — to make authoritative game logic decisions based on flag values — use the Satori client within the Nakama server runtime.

```go
satoriClient := nk.GetSatori()
flags, err := satoriClient.FlagsList(ctx, "<identity_id>")
```

This returns the same resolved values a client SDK call would return for that identity. Server-side flag reads are useful when you need to enforce flag-driven logic authoritatively — adjusting matchmaking parameters or validating reward amounts before granting them, for example.

Review all available functions for your preferred Nakama runtime:

- [Go runtime function reference](/nakama/server-framework/function-reference/go/)
- [TypeScript runtime function reference](/nakama/server-framework/function-reference/typescript/)

## Inspect a player's resolved flags

To see exactly what a specific player is receiving and why, use **Player View** in the Satori console. Open an identity, then go to the **Feature Flags** tab to see every flag resolved for that player, the value they're receiving, and the override source (default, variant, live event, or experiment).

<!-- IMAGE: [The Feature Flags tab in Player View, showing a flag with its resolved value and override source] -->

If you've changed a flag variant and a player isn't seeing the expected value, the inspector tells you whether an experiment or live event is taking precedence — so you can trace the resolution directly rather than guessing.
