# Feature flags (/docs/feature-flags)

A feature flag is a key your server code checks, such as `double-xp-weekend`. In RoChart you decide which players get it, and you can change that at any time without publishing a new version of your place.

- **Boolean flags** are on or off: *turn the new map on for 10% of players*.
- **Multivariate flags** return a variant, such as `control`, `short` or `skip`, each with its own share and an optional payload. [Experiments](/docs/experiments) run on these.

```luau
if RoChart.isFeatureEnabled(player, "new-map") then
  teleportToNewMap(player)
end
```

Flags are evaluated on the game server, per player, so players can't pick their own value from the client.

## Create a flag [#create-a-flag]

**Feature flags → New flag.**

1. Set a **Key** (letters, numbers, `-` and `_`), and optionally a name and description.
2. Set the **Release conditions**: who gets the flag. See below.
3. Choose the **Served value**: **Boolean** or **Multivariate**.
4. Optionally add **Payloads**.
5. Switch it on. New flags start off.

The **Implementation** panel shows a ready-to-copy snippet for your code, with a Copy Prompt for your coding agent. See [Flags in your code](/docs/feature-flags/in-code).

## Who gets it [#who-gets-it]

Release conditions are a list of **condition sets**, checked from top to bottom. Each set has:

- **conditions**, which must all match. No conditions means everyone.
- a **rollout percentage**: the share of matching people who get the flag.

A person gets the flag from the first set they match *and* whose rollout includes them. Otherwise RoChart checks the next set. Nobody matched? The flag is off for them. So put specific rules on top and the broad catch-all at the bottom:

1. In cohort *Testers* (a static cohort of your team's UserIds), 100%: the team always sees it.
2. In cohort *Power players*, 50%.
3. Everyone, 5%.

Conditions can check:

- **Person properties**, such as `platform` equals `Phone`, `premium` is `true` or `country` is one of `DE, NL`. These are the [player properties](/docs/getting-started/identify) the module sets, plus your own from `setUserProperties`.
- **Cohorts**, in or not in. This is how you target behaviour, such as *power players* or *players who haven't bought anything in 90 days*. Cohort changes reach flags within about five minutes.
- **Group properties**, when the flag [matches by group](#match-by-group).

Players RoChart hasn't seen yet are never in a cohort.

### Rollout percentages are stable [#rollout-percentages-are-stable]

- **The same player always gets the same value**, on every server and every device.
- **Raising the rollout only adds people.** Going from 10% to 30% keeps the first 10%, so nobody flips back and forth.
- **Flags are independent.** Being in the first 10% of one flag says nothing about another.

## Variants [#variants]

Choose **Served value → Multivariate** and add variants with a key and a share. The shares must add up to 100. Everyone a condition set lets in gets one variant, and keeps it.

A condition set can also **Force** one variant instead of **Split by variant percentages**. Use it to always show your testers the new version, or to keep a segment on `control`.

Changing the shares later moves some people to another variant. Don't do that during a running experiment.

## Payloads [#payloads]

A payload is a piece of JSON attached to a variant, or to "on" for a boolean flag. Use it for numbers and settings you want to tune without publishing, such as a reward amount or a cooldown:

```json
{ "short": { "steps": 3 }, "skip": { "steps": 0 } }
```

The browser and Node SDKs read payloads with `getFeatureFlagPayload`. The Luau module returns the flag's value; payloads are returned by [`POST /i/flags`](/docs/reference/sdk#post-iflags).

## Match by group [#match-by-group]

Set **Match by** to a group type to decide the flag **per group** instead of per player, so everyone in one group gets the same value. Conditions can then check the group's properties. The browser and Node SDKs pass the group with each check. The Luau module's `getFlag` checks per player, so in a game, use flags that match by person. Without a group, the flag is off.

## Test a user [#test-a-user]

Before you widen a rollout, open the flag and use **Test a user**. Enter a UserId or username to see this flag's value and payload for that player, plus every other flag they'd get.

## Turn it off [#turn-it-off]

Switching a flag off turns it off for everyone immediately. It's your kill switch. Your code then sees the flag as unknown (`nil` in Luau), so always have a default path.

## Flags used by experiments [#flags-used-by-experiments]

Every experiment creates its own flag. While the experiment runs, you can't change its variant keys, and the flag can't be deleted. When you conclude an experiment, you can roll the winner out to everyone through the same flag, and your code keeps working unchanged.
