---
title: "フィーチャートグル（Feature Toggle）とは？機能フラグ4種類の使い分けと実装例・削除までの運用"
url: "https://www.issoh.co.jp/tech/details/9336/"
published: 2025-10-16
updated: 2026-11-08
categories: ["CI/CD"]
publisher: "株式会社一創"
---

# フィーチャートグル（Feature Toggle）とは？機能フラグ4種類の使い分けと実装例・削除までの運用

フィーチャートグル（Feature Toggle）は、コードを本番へデプロイしたまま、機能を有効にするかどうかを設定値で切り替える手法です。フィーチャーフラグ（feature flag）、機能フラグ、feature switchとも呼ばれ、指しているものは同じです。仕組みはif文1つで済みますが、目的の違うフラグを同じように扱うと、使い終わった分岐がコードに残り続けます。

この記事では、Pete HodgsonがMartin Fowlerのサイトで整理した4種類の分類を軸に、設定の置き場所、Pythonで動かした段階公開の実装例、社内公開から全員公開までの進め方、ツールの選び方、期限切れのフラグをCIで止める方法までを扱います。

## まとめ：フィーチャートグル導入で決めておく5項目

- **種類を決める**：Release・Experiment・Ops・Permissionのどれかを作成時に決めます。寿命と、切り替えの動的さが種類ごとに違います。
- **削除期限と担当者を台帳に書く**：Release Toggleは1〜2週間程度で消す前提です。期限切れをCIで検出すれば、削除漏れに気づけます。台帳とコードの両方から不要なフラグを除く運用も必要です。
- **振り分けは決定的にする**：段階公開ではユーザーIDのハッシュで振り分けます。乱数で振り分けると、アクセスのたびに表示が変わります。
- **フラグ名を使い回さない**：Knight Capitalは旧機能のフラグを新機能に転用し、4億6,000万ドルの損失を出しました。
- **ツールは長く残るフラグの数で選ぶ**：短命のフラグが数本なら設定ファイルで足ります。PermissionやOpsのフラグが増え、エンジニア以外も切り替えるようになったら、管理画面と変更履歴のある仕組みへ移します。

## フィーチャートグルの定義と別名

Pete Hodgsonは[Feature Toggles (aka Feature Flags)](https://martinfowler.com/articles/feature-toggles.html)で、フィーチャートグルをコードを変えずにシステムの振る舞いを切り替える手法として説明しています。[日本語版Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%BC%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88%E3%82%B0%E3%83%AB)は別名として、feature switch（機能スイッチ）、feature flag（機能フラグ）、feature flipper、conditional featureを挙げています。「feature toggle」と「feature flag」の違いを問われることがありますが、呼び方の違いで、仕組みに差はありません。

### デプロイとリリースを分ける仕組み

フィーチャートグルを使うと、コードを本番環境に置くこと（デプロイ）と、利用者に機能を見せること（リリース）が別の操作になります。フラグがOFFの間、分岐先の新しい処理は呼ばれません。分岐の外に置いた初期化処理などは動くので、隠したい処理はすべてフラグの内側に入れます。設定を実行中に読み直せる仕組みなら、フラグをONにするだけで公開でき、再デプロイは要りません。

問題が見つかったときは、フラグをOFFにして以後の処理を旧経路へ戻せます。ただし、戻せるのはコードの経路だけです。すでに書き込まれたデータや外部へ送った通知は取り消せません。

### フィーチャーブランチ・トランクベース開発との違い

フィーチャーブランチでは、未完成の機能をGitのブランチで隔離します。フィーチャートグルでは、未完成の機能もメインブランチへマージし、実行時の条件分岐で隔離します。ブランチが長く分かれたままだとマージ時の衝突が大きくなりますが、トグルならその問題は起きにくくなります。代わりに、コードの中に分岐が残るという負担を抱えます。

変更を毎日メインブランチへ統合するトランクベース開発では、未完成の機能を本番で隠す手段の1つがRelease Toggleです。必須ではなく、機能の分割や後述のKeystone Interfaceで足りる場合もあります。1〜2日で終わる作業は短命のブランチで進め、数週間かかる機能のうち先に本番へ置く部分だけをトグルで隠す、という併用が現実的です。ブランチの種類と運用の基本は[Gitブランチの種類とブランチ戦略の解説](/tech/details/3892/)で扱っています。

## フィーチャートグル4種類の寿命と動的性

Hodgsonが2017年10月9日に更新した原典は、フラグを目的別に4種類へ分けています。種類によって、どれだけ長く残るか（寿命）と、どれだけ細かく判定が変わるか（動的性）が大きく違います。

| 種類                | 主な用途      | 寿命（Hodgson）  | 動的性     | Unleashの想定寿命       |
| ----------------- | --------- | ------------ | ------- | ------------------ |
| Release Toggle    | 未完成機能を隠す  | 1〜2週間程度      | 非常に静的   | 40日                |
| Experiment Toggle | A/Bテスト    | 数時間〜数週間      | 非常に動的   | 40日                |
| Ops Toggle        | 負荷時の機能停止  | 多くは短命・一部は無期限 | 即時変更が必要 | 7日（Kill switchは恒久） |
| Permission Toggle | 有料・社内向け機能 | 複数年に及ぶ       | 非常に動的   | 恒久                 |

Release Toggleは「transitionary by nature」、つまり移行期間のためのもので、判定は全利用者で同じ値になり、切り替えるのも公開のときだけです。Experiment Toggleは統計的に有意な結果が出るまでの間だけ使い、利用者がどの群に属するかでリクエストごとに結果が変わります。Ops Toggleの多くは新機能の運用に確信が持てた時点で役目を終えますが、負荷が高いときに重い処理を止めるキルスイッチはほぼ無期限に残し、障害時にすぐ切り替えられるようにしておきます。Permission Toggleは有料プランや社内だけに見せる機能を制御し、利用者ごとに判定します。

管理ツールも同じ考え方で期限を持たせています。[Unleashのフラグ種類](https://docs.getunleash.io/concepts/feature-flags)では、ReleaseとExperimentの想定寿命が40日、Operationalが7日、Kill switchとPermissionが恒久と既定で決まっており、想定寿命を過ぎたフラグは自動で「potentially stale」と表示されます。LaunchDarklyの[Flag health](https://launchdarkly.com/docs/home/releases/flag-health)も、一時的なフラグが作成から30日以上たち、inactiveまたはlaunchedの状態が7日以上続くとstaleと判定します。日数はHodgsonの1〜2週間より長めですが、種類によって期限を設けるかどうかを分けている点は共通です。

この表から導ける実務上の判断は1つです。**短命のRelease・Experiment・多くのOpsフラグと、長期運用するキルスイッチやPermissionフラグでは、期限ルールを分けます**。期限のないキルスイッチにまで削除期限を課すと、障害時に必要なスイッチまで消されます。

## フィーチャートグルの構成要素と設定の置き場所

### Toggle Point・Router・Context・Configurationの役割分担

Hodgsonの記事は、フィーチャートグルの実装を次の4つの要素に分けて説明しています。

- **Toggle Point**：コードの中で、フラグを見て処理を分岐させる箇所
- **Toggle Router**：フラグがONかOFFかを実際に判定する部品
- **Toggle Context**：判定に使う情報（ユーザーID、プラン、国、社内からのアクセスかどうか）
- **Toggle Configuration**：どの条件でONにするかの設定

Toggle Pointに判定条件を直接書くと、同じ条件がコードのあちこちに散らばり、あとで削除するときに漏れが出ます。判定はToggle Routerにまとめ、Toggle Pointでは「このフラグは有効か」を問い合わせるだけにします。原典はこれを「decision point（分岐する場所）とdecision logic（判定の理屈）の分離」と呼んでいます。

Toggle Pointをどこに置くかも決めておきます。ユーザーごとの判定が要るExperimentやPermissionのフラグは、リクエストが最初に届く画面やAPIの入口（edge）に置くと、判定に必要な情報が揃い、内部のロジックに分岐が入り込みません。

### 設定の置き場所5方式と切り替えに必要な操作

Toggle Configurationをどこに保存するかで、フラグを切り替えるのに何が必要かが決まります。Hodgsonの原典が挙げる5つの方式を、切り替え時の操作で並べると次のとおりです。

| 保存場所                       | 切り替えに必要な操作  | 向くフラグ           |
| -------------------------- | ----------- | --------------- |
| コードに直書き（コメントアウト・#ifdef）    | ビルドと再デプロイ   | Release         |
| 起動引数・環境変数                  | 再起動         | Release・環境ごとの切替 |
| 設定ファイル（YAML・JSON）          | 多くは再デプロイ    | Release         |
| アプリのDB＋管理画面                | 画面から即時      | Permission・Ops  |
| 分散KVS（etcd・Consul等）・管理サービス | 即時・全サーバーへ配信 | Experiment・Ops  |

原典は、フラグの性質が許すなら**ソース管理された静的な設定と再デプロイで切り替える方を勧めています**（Prefer static configuration）。設定がコードと同じCI/CDパイプラインを通るため、どの設定で何が動いているかをビルド単位で再現できるからです。動的に設定を変更する仕組みが必要なのは、障害時にすぐ止めたいOps Toggleなどです。Experiment・Permission Toggleの利用者別判定は、静的な設定でも実装できます。Release Toggleだけのために管理サービスを入れる必要はありません。

## 実装例：Pythonで作る段階公開つきトグルルーター

次のコードは、Toggle Routerを最小限の形で実装したものです。フラグ全体のON/OFF、特定ユーザーの許可リスト、全体の何%に公開するかの3つを扱います。設定はプロセス内のメモリに置いており、複数プロセス間の同期や外部からの設定更新は含みません。Python 3.14.6で実行しました。

```
import hashlib

FLAGS = {
    "new-checkout": {"enabled": True, "rollout_percent": 10, "allow_users": {"qa-001"}},
}

def bucket(flag_key: str, user_id: str) -> int:
    digest = hashlib.sha256(f"{flag_key}:{user_id}".encode()).hexdigest()
    return int(digest[:8], 16) % 100

def is_enabled(flag_key: str, user_id: str) -> bool:
    flag = FLAGS.get(flag_key)
    if flag is None or not flag["enabled"]:
        return False
    if user_id in flag["allow_users"]:
        return True
    return bucket(flag_key, user_id) < flag["rollout_percent"]

if __name__ == "__main__":
    users = [f"user-{i}" for i in range(10000)]
    print("ON:", sum(is_enabled("new-checkout", u) for u in users), "of", len(users))
    print("user-7 bucket:", bucket("new-checkout", "user-7"),
          "results:", {is_enabled("new-checkout", "user-7") for _ in range(100)})
    on10 = {u for u in users if is_enabled("new-checkout", u)}
    FLAGS["new-checkout"]["rollout_percent"] = 50
    on50 = {u for u in users if is_enabled("new-checkout", u)}
    print("ON at 50%:", len(on50), "kept from 10%:", len(on10 & on50))
    FLAGS["new-checkout"]["enabled"] = False
    print("kill switch, qa-001:", is_enabled("new-checkout", "qa-001"))
```

実行結果は次のとおりです。

```
ON: 1020 of 10000
user-7 bucket: 63 results: {False}
ON at 50%: 4933 kept from 10%: 1020
kill switch, qa-001: False
```

### ハッシュで振り分けを固定する理由

10%に設定すると、1万人中1,020人がONになりました。user-7のバケット値は63なので、100回判定しても結果は毎回Falseです。乱数で振り分けると、同じ人がページを開くたびに新しい画面と古い画面を行き来してしまいます。フラグ名とユーザーIDを連結してハッシュにかけるのはこれを防ぐためで、フラグ名も含めているので、フラグごとに異なる振り分けを作れます。ただし、バケットは100個なので、別のフラグでも同じバケットに入る場合があります。

公開範囲を50%に広げるとONは4,933人になり、10%の段階でONだった1,020人は全員が50%でもONのままでした（出力の kept from 10%）。バケット値は変わらず、しきい値が上がるだけなので、一度新機能を見た人が段階を進めた途端に古い画面へ戻ることはありません。

最後の行は、enabledをFalseにすると、許可リストに入っているqa-001も含めて全員がOFFになることを示しています。キルスイッチは許可リストより先に判定しないと効きません。

### OpenFeatureの評価APIとProviderによるベンダー依存の分離

[OpenFeature](https://openfeature.dev/specification/)は、フィーチャーフラグを評価するAPIを標準化するプロジェクトです。2022年6月17日にCNCFに採択され、2023年11月21日にIncubatingへ移行しました（2026年11月8日時点もIncubating）。アプリケーションはOpenFeatureのAPIだけを呼び、実際のフラグ管理システムとの間はProviderが仲介します。仕様には、判定に使う情報を渡すEvaluation Contextと、評価のbefore・after・error・finallyの4段階に処理を差し込むHooksも定められています。Providerとフラグ管理システムの間の通信についても、[OFREP（OpenFeature Remote Evaluation Protocol）](https://openfeature.dev/specification/appendix-c/)というベンダーに依存しない評価プロトコルが仕様の付録Cにまとめられています。

次のコードは、openfeature-sdk 0.10.0（2026年11月8日時点のPyPI最新版）に含まれるInMemoryProviderで動かした例です。`python -m pip install openfeature-sdk==0.10.0`で導入してから実行します。

```
from openfeature import api
from openfeature.evaluation_context import EvaluationContext
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider

api.set_provider(InMemoryProvider({
    "new-checkout": InMemoryFlag(
        default_variant="off",
        variants={"on": True, "off": False},
    ),
}))
client = api.get_client()
ctx = EvaluationContext(targeting_key="user-42")

details = client.get_boolean_details("new-checkout", False, ctx)
print(details.value, details.variant, details.reason)

missing = client.get_boolean_details("typo-flag", False, ctx)
print(missing.value, missing.reason, missing.error_code)
```

```
False off STATIC
False ERROR FLAG_NOT_FOUND
```

注目したいのは2行目です。存在しないフラグ名を渡しても例外は発生せず、呼び出し側が指定した既定値のFalseが返ります。フラグ名を打ち間違えると、機能は黙ってOFFのままになります。OpenFeatureを使う場合は、戻り値のreasonとerror\_codeを確認するか、errorフックで記録し、フラグ名は定数にまとめて文字列を直接書かないようにします。

## 社内公開から全員公開までの進め方

フラグを作ってから消すまでの流れを、段階ごとに区切ると次のようになります。実装例の allow\_users と rollout\_percent がそれぞれの段階に対応します。

1. **OFFのままマージ**：未完成のコードをフラグOFFでメインブランチに入れ、本番へデプロイします。
2. **社内だけON**：許可リストや社内ネットワークの判定で、開発者や他部署の担当者だけが本番で新機能を触れるようにします。
3. **1%→10%→50%と拡大**：エラー率や応答時間を見ながら、ハッシュ振り分けの割合を上げます。悪化したらOFFに戻します。
4. **100%公開**：全員に公開し、旧経路が使われていないことをログで確かめます。
5. **分岐と旧コードを削除**：まずコード中のフラグ参照と旧処理を削除してデプロイします。外部管理サービスの設定は、旧バージョンからの参照や切り戻しへの影響を確認してから削除します。同梱する静的設定なら、コードと同じプルリクエストで削除できます。

2の段階の具体例として、PR TIMESはPHPカンファレンス2022の登壇[「ローンチから16年目のWebサービスに、どうやってフィーチャートグルを導入したか、運用しているか」](https://speakerdeck.com/meihei3/phpcon2022-e259c9cb-1462-4e0a-b22c-20327532bbee)で、Release Toggleを基本OFFにしたまま、オフィスやVPNのIPアドレスから社内のアクセスを判定し、社内だけがCookieでフラグを切り替えられる仕組みを紹介しています。目的として、エンジニア以外の人がリリース前に変更内容を確認できることを挙げています。

3の段階は[カナリアリリース](/tech/details/13592/)の一種です。カナリアリリースはサーバー単位でも利用者単位でも実施でき、フィーチャートグルは利用者単位で振り分ける手段になります。ユーザーIDのハッシュで振り分けるため、ログイン済みの利用者に一貫した体験を保てます。メトリクスを見ながら拡大と切り戻しを自動で判断する運用は[プログレッシブデリバリーの自動分析と昇格判断](/tech/details/16194/)で、利用者に見せずに本番トラフィックで新しい処理だけを動かす方法は[ダークローンチによる裏側の検証](/tech/details/16208/)で扱っています。

A/Bテストに使う場合はExperiment Toggleとして扱い、結果が出たらフラグと負けた側のコードを両方削除します。

## フィーチャートグル管理ツールの選び方

管理ツールを選ぶときの目安は、長く残るフラグの数と、エンジニア以外の人がフラグを切り替えるかどうかです。短命のReleaseフラグが数本しかないなら、上の実装例のように設定ファイルや環境変数で十分です。

| ツール                  | 形態                    | 版・提供状況（2026年11月8日時点）  |
| -------------------- | --------------------- | --------------------- |
| Unleash              | OSS（AGPL-3.0）         | v8.3.1（2026年10月29日）   |
| flagd                | OpenFeatureのOSS評価エンジン | v0.18.2（2026年10月28日）  |
| Flipper              | Ruby gem（MIT）         | 1.4.2（2026年5月11日）     |
| GitLab Feature Flags | GitLabの機能             | Free・Premium・Ultimate |
| AWS AppConfig        | AWSのマネージドサービス         | 定義済みデプロイ戦略4種          |
| LaunchDarkly         | SaaS                  | booleanとmultivariate  |

OSSを自社で運用するなら、Unleashとflagdが候補になります。[UnleashのリポジトリはAGPL-3.0](https://github.com/Unleash/unleash)なので、改変して外部に提供する場合はライセンス上の義務を確認してください。[GitLab Feature Flags](https://docs.gitlab.com/operations/feature%5Fflags/)はUnleash互換のAPIを提供しており、アプリケーション側ではUnleash互換のクライアントライブラリをそのまま使えます。振り分けの戦略はAll users・Percent Rollout・Percent of Users・User IDs・User Listの5つで、Freeプランから使えるため、GitLabを使っているなら追加の基盤なしで始められます。

RailsアプリならFlipperが手軽です。フラグの状態をActiveRecordやRedisに保存できるので、アプリを動かしたまま切り替えられます。

AWS上のアプリなら[AWS AppConfig](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-deployment-strategy-predefined.html)が候補です。構成プロファイルのタイプにAWS.AppConfig.FeatureFlagsを指定するとフラグ専用の形式で管理でき、配信にはAppConfig.Linear20PercentEvery6Minutes・AppConfig.Canary10Percent20Minutes・AppConfig.AllAtOnce・AppConfig.Linear50PercentEvery30Secondsの4つの定義済み戦略が用意されています。配信中に指定したCloudWatchアラームがALARMかINSUFFICIENT\_DATAになると、設定は前のバージョンへ自動で戻ります（アラームのアクションを無効にしている場合は戻りません）。この段階配信は設定データを取りに来るアプリ側へ徐々に広げる仕組みで、利用者の何%に見せるかの振り分けとは別物です。利用者単位の段階公開には、[マルチバリアントフラグのsplit演算子](https://docs.aws.amazon.com/appconfig/latest/userguide/appconfig-creating-multi-variant-feature-flags-rules-operators.html)を使うと、ユーザーIDなどのハッシュで指定した割合へ振り分けられます。

LaunchDarklyのようなSaaSが向くのは、プロダクト担当者が管理画面から公開範囲を操作し、変更履歴を監査する必要がある場合です。フラグはtrue/falseのbooleanと、文字列・数値・JSONで2つ以上の値を持てるmultivariateの2種類で、[Code References](https://launchdarkly.com/docs/home/flags/code-references)を使うとld-find-code-refsがリポジトリを走査し、フラグがコードのどこで参照されているかを管理画面に送ります。料金の数え方とNode.jsでの実装、UnleashなどOSSとの選び分けは[LaunchDarklyとは？料金の数え方とNode.js実装](/tech/details/19161/)で整理しています。モバイルアプリの条件配信なら[Firebase Remote Configの条件配信と段階ロールアウト](/tech/details/17048/)、製品分析と同じSDKでフラグを配信したいなら[PostHogのフラグ導入手順と料金の試算](/tech/details/18705/)も選択肢に入ります。

どのツールを選ぶ場合でも、アプリケーションからはOpenFeatureのAPIを呼ぶ形にしておくと、後で乗り換えるときに評価APIの呼び出し部分の変更を抑えられます。ただし、移行先のProviderの有無と、フラグ定義・評価条件・認証設定の移し替えは別に確認が要ります。フラグ管理をCI/CDの整備とあわせて進める場合は、弊社の[DevOps・CI/CD導入支援](/service/system/devops/)でも相談を受けています。

## フィーチャートグルのデメリットと失敗事例

### テストすべき組み合わせの増加

フラグが1本増えるたびに、理論上の設定の組み合わせは2倍になります。フラグが10本あれば1,024通りで、すべてを試すのは現実的ではありません。Hodgsonは、少なくとも本番で有効になる予定の設定、つまり現在の本番設定に、これからONにするフラグを加えた組み合わせをテストするよう勧めています。あわせて、公開予定のフラグをOFFに戻したフォールバック設定もテストします。

### フラグの再利用が招いた4億6,000万ドルの損失

米証券取引委員会（SEC）の[命令文（Release No. 34-70694）](https://www.sec.gov/litigation/admin/2013/34-70694.pdf)によると、Knight Capitalは2012年8月1日、ニューヨーク証券取引所のRetail Liquidity Program（RLP）に対応する新しいコードを有効にするために、廃止済みの機能「Power Peg」に使っていたフラグを再利用しました。ところが、8台のサーバーのうち1台には新しいコードが配置されておらず、Power Pegの古いコードが残っていました。フラグをONにした結果、そのサーバーで古い機能が動き出し、大量の意図しない注文が出されました。Knightはこのポジションで4億6,000万ドルの損失を計上しています。

原因は2つに分けられます。使い終わったフラグの分岐を削除していなかったことと、同じ名前のフラグに別の意味を持たせたことです。フラグ名は一度使ったら再利用しない。廃止した機能のコードは、フラグと一緒に削除する。この2点は旧機能の誤作動を防ぐ対策です。加えて、全サーバーへの配備確認、注文量の制限、異常時の停止手順も必要です。

## フィーチャートグルを残さない運用ルール

### 不要なフラグの削除期限・担当者・完了条件

Hodgsonは、フラグを保有コストのかかる在庫として扱うよう勧めています。原典の提案（削除タスク・期限・本数上限）に、命名と完了判定の運用例を加えると次のようになります。

- **作成時に削除タスクを起票する**：Release Toggleなら、公開予定日から2週間後を期限にします。
- **期限切れでテストを失敗させる**：期限を過ぎたフラグが残っているとテストが落ちる、時限爆弾（time bomb）型のチェックを入れます。
- **本数に上限を設ける**：チームごとに有効なフラグの上限を決め、新しく作るには既存のフラグを1本消す運用にします。
- **名前に種類を入れ、担当者を台帳に書く**：release.checkout-v2 のように種類を接頭辞にすると、一覧を見るだけで期限のあるフラグかどうかがわかります。
- **削除の完了を分岐の削除で判定する**：管理画面でフラグを消しても、コードのif文が残っていれば削除したことにはなりません。

### 台帳と期限切れチェックをCIに入れる実装例

原典は、構造化した設定ファイルに作成日・担当者・期限を書いておくことを勧めています。次の例は、flags.jsonの期限と、src配下のPythonコードにある限定的な書式の参照を調べる簡易スクリプトです。未登録フラグの検出対象は、is\_enabledの直後に開き括弧と二重引用符が続く呼び出しだけで、単一引用符・空白・改行・変数を使った参照は検出できません。検出した違反をマージ阻止につなげるには、このスクリプトの終了コードをCIへ伝え、そのチェックの成功をマージ条件に設定します。検出対象外の参照や台帳だけの削除は、この例では防げません。

```
{
  "release.new-checkout": {"type": "release", "owner": "team-pay", "expires": "2026-11-01"},
  "release.search-v2":    {"type": "release", "owner": "team-search", "expires": "2026-11-20"},
  "ops.recommend-kill":   {"type": "ops", "owner": "team-sre", "expires": null},
  "permission.export-csv": {"type": "permission", "owner": "team-biz", "expires": null}
}
```

```
import json, pathlib, re, sys
from datetime import date

TODAY = date.fromisoformat(sys.argv[1]) if len(sys.argv) > 1 else date.today()
registry = json.loads(pathlib.Path("flags.json").read_text())
code = "\n".join(p.read_text() for p in pathlib.Path("src").rglob("*.py"))
used = set(re.findall(r'is_enabled\("([^"]+)"', code))

errors = []
for key, meta in registry.items():
    if meta["type"] in ("release", "experiment") and meta["expires"] is None:
        errors.append(f"{key}: 短命の種類なのに期限がない")
    if meta["expires"] and date.fromisoformat(meta["expires"]) < TODAY:
        errors.append(f"{key}: 期限 {meta['expires']} 切れ（担当 {meta['owner']}）")
for key in sorted(used - registry.keys()):
    errors.append(f"{key}: コードにあるが台帳にない")

print("\n".join(errors) or "OK")
sys.exit(1 if errors else 0)
```

src配下に release.new-checkout・release.search-v2・release.old-banner の3つを参照するコードを置き、日付を2026-11-08として実行した結果です（Python 3.14.6）。

```
$ python check_flags.py 2026-11-08
release.new-checkout: 期限 2026-11-01 切れ（担当 team-pay）
release.old-banner: コードにあるが台帳にない
$ echo $?
1
```

OpsとPermissionのフラグは期限をnullにして対象外にし、ReleaseとExperimentで期限が空なら逆にエラーにしています。種類ごとに期限の扱いを変えるルールを、レビューの注意ではなくコードで強制する形です。

### 稼働中のフラグ設定を確認する運用者向けエンドポイント

原典は、ビルド番号を確認できるようにするのと同じく、稼働中のシステムのフラグ設定を運用者が確かめられる手段を用意するよう勧めています。HTTPのサービスならメタデータ用のエンドポイントを設けるのが一般的で、例としてSpring BootのActuatorを挙げています。障害対応中に「いまどのフラグがONか」を調べられないと、切り戻しの判断が遅れます。台帳には、運用者が読んで意味のわかる説明文も添えておきます。

## フィーチャートグルを使うべきでない場面

Martin Fowlerは[Bliki記事「FeatureFlag」](https://martinfowler.com/bliki/FeatureFlag.html)で、Release Flagの有用性を認めつつも「they should be your last choice」、つまり最後の選択肢にすべきだと書いています。先に検討すべきなのは、機能を小さく分割して1つずつ公開する方法と、裏側の実装を先に本番へ置いて利用者が触れる入口（画面やAPIの公開部分）を最後に足すKeystone Interfaceです。

次の条件に当てはまる場合は、トグルを使わない方が安全です。

- 作業が1〜2日で終わり、ブランチを短く保てる
- データベースのスキーマ変更を伴い、ONとOFFで互換性のないデータが書き込まれる
- 入口を最後に作る設計が取れる（Keystone Interfaceで足りる）
- チームにフラグを削除する担当と期限の運用がまだ無い

スキーマ変更を伴う機能でフラグを当てにすると、OFFに戻してもデータは戻らず、新形式のデータを旧コードが読めずに障害が広がります。この場合は、新旧どちらのコードでも読めるようにスキーマを先に拡張し、データ移行を終えてから旧形式を消す順で進め、フラグはコード経路の切り替えだけに使います。インフラ単位で新旧の環境を切り替える方法は[Blue/Greenデプロイの仕組みとカナリアとの違い](/tech/details/4040/)で扱っています。

## よくある質問

### フィーチャートグルとフィーチャーフラグは違うものですか？

同じものを指します。Feature Toggle、Feature Flag、機能フラグ、feature switchはいずれも、コードを変えずに設定値で機能のON/OFFを切り替える手法の呼び名です。

### フィーチャートグルの種類は？

Pete Hodgsonの分類では、Release・Experiment・Ops・Permissionの4種類です。Releaseは1〜2週間程度の短命なフラグ、Permissionは複数年残ることもある長寿命のフラグで、種類によって削除期限の決め方が変わります。

### フィーチャートグルのデメリットは？

コードに条件分岐が増え、テストすべき設定の組み合わせも増えることです。使い終わったフラグを消さずに残すと技術的負債になり、Knight Capitalの2012年の事故のように、古いフラグを再利用して大きな損失を出した例もあります。

### キルスイッチとは何ですか？

障害や高負荷のときに、特定の機能をすぐ止めるためのOps Toggleです。多くのOps Toggleは短命ですが、キルスイッチは長く残すことが多いため、削除期限のあるフラグとは別に管理します。判定では、許可リストより先にキルスイッチを評価します。

### フィーチャートグルは自前で実装すべきですか？

短命のフラグが数本なら、設定ファイルと数十行のコードで足ります。長寿命のフラグが増えた場合や、エンジニア以外の人が切り替える場合は、UnleashやLaunchDarkly、AWS AppConfigなどに移します。アプリケーション側でOpenFeatureのAPIを使っておくと、移行時の書き換えが少なく済みます。

## 関連記事

- [カナリアリリースとは？段階リリースの仕組み・他方式との違い・実装と採用判断を実装視点で解説](/tech/details/13592/)
- [プログレッシブデリバリーとは？自動分析で昇格とロールバックを判断する実装と採用基準](/tech/details/16194/)
- [ダークローンチとは？本番トラフィックで裏側だけ検証する実装と採用判断](/tech/details/16208/)
- [LaunchDarklyとは？料金の数え方とNode.js実装、Unleash等OSSとの選び分け【2026年11月時点】](/tech/details/19161/)
- [Blue/Greenデプロイとは？仕組み・カナリアとの違いとKubernetes・AWS・RDSでの実装](/tech/details/4040/)

---

出典: [フィーチャートグル（Feature Toggle）とは？機能フラグ4種類の使い分けと実装例・削除までの運用](<https://www.issoh.co.jp/tech/details/9336/>)（株式会社一創）
