---
title: Flagpole concepts
description: Understand default switches, percentage rollouts, environments, tags, history, persistence, and webhooks.
url: https://pr-14-c0fdf0ef9f59.thally.app/flagpole/concepts
---

# Flagpole concepts

Understand default switches, percentage rollouts, environments, tags, history, persistence, and webhooks.

Flagpole stores boolean release decisions behind one HTTP API. A flag's key is
immutable; its state and optional metadata can change over time.

## Flags and default switches

A flag has a `key`, an `enabled` default switch, optional `description`, optional
`rolloutPercentage`, optional `tags`, and creation and update timestamps. Keys
contain 1–64 letters, digits, dots, dashes, or underscores.

Without an environment override, `enabled: false` turns evaluation off for
everyone regardless of the rollout percentage. An environment override can
replace that value for its environment, so treat the flag value as the default
switch rather than a global kill switch. Use `POST /v1/flags/:key/toggle` for an
atomic, body-free change to the default. Use `GET /v1/flags/:key/status` when a
client needs only that default state.

## Deterministic percentage rollouts

Set `rolloutPercentage` to an integer from `0` through `100`, then evaluate with
a stable `unit`, such as a user or account id:

```bash
curl -s 'http://localhost:3333/v1/flags/new-checkout/evaluate?unit=account-42'
```

Flagpole hashes the flag key and unit into a bucket from 0 through 99. The same
pair always receives the same decision, and increasing the percentage only
adds units to the cohort. Without `unit`, evaluation returns the flag's plain
boolean. `GET /v1/flags/:key/rollout` returns the policy without the full flag.

## Environment overrides

`development`, `staging`, and `production` exist when the process starts. Add
another lowercase kebab-case environment with `POST /v1/environments`.

An override replaces `enabled`, `rolloutPercentage`, or both for one flag and
environment. Unspecified values fall back to the flag defaults:

```bash
curl -s -X PUT \
  http://localhost:3333/v1/flags/new-checkout/environments/staging \
  -H 'content-type: application/json' \
  -d '{"enabled":true,"rolloutPercentage":100}'

curl -s \
  'http://localhost:3333/v1/flags/new-checkout/evaluate?environment=staging&unit=account-42'
```

Evaluating an unknown environment returns `404 environment_not_found`.
Deleting a flag also clears all of its overrides.

## Tags and list projections

Each flag can carry up to 10 unique lowercase kebab-case tags of at most 50
characters. A `PATCH` replaces the complete tag set. The tag-specific `PUT`
and `DELETE` routes add or remove one tag idempotently, which is safer for
concurrent labelers.

Use `GET /v1/flags?tag=checkout` to filter full flags, `GET /v1/tags` for tag
counts, and `GET /v1/flags/:key/tags` for one flag's tag-only projection.
`GET /v1/flags` also accepts `page` and `perPage`; `perPage` cannot exceed 200.

## Change history

Flagpole records `created`, `updated`, and `deleted` events. History survives
flag deletion and stays ordered oldest first. `?limit=20` returns the most
recent suffix while preserving that order. A key that never existed returns
`404 flag_not_found`.

## Persistence boundaries

Without `FLAGPOLE_DATA_FILE`, flags and history live only in memory. With a
path, flag mutations rewrite one JSON file atomically. Webhooks, their delivery
records, environment definitions, and overrides are in-memory registries in
the current release; restarting the process resets them.

## Webhook records

Subscriptions accept an HTTPS URL, one or more of `flag.created`,
`flag.updated`, `flag.deleted`, and `tag.retired`, plus an optional secret of at
least 16 characters. The current release automatically records
`flag.deleted`; the test endpoint records the subscription's first selected
event. It does not yet generate the other event types or send HTTP requests.
Your application owns actual transport and retries.

Continue to the [Flagpole API summary](/guides/flagpole-api) or the complete
[generated endpoint reference](/api/default/health/get).