GitOps Flag Sync
Treat feature flags as versioned source code. Sync your flag targeting rules directly from Git repositories using declarative manifests.
ToggleAI's GitOps Flag Sync (Flags-as-Code) service enables developers to manage feature flag configurations via pull requests rather than manual console edits. By declaring targeting rules, percentage rollouts, and variants in a version-controlled YAML config file (.toggleai/flags.yaml), every configuration change is audited in your git history, peer-reviewed before it goes live, and automatically synchronized to ToggleAI's edge runtime.
This approach aligns feature flag management with standard software delivery practices — the same review, approval, and deployment workflows your team already uses for code now govern flag changes. Rollbacks are as simple as reverting a commit.
Under the hood, the GitOps Engine is a background service inside the ToggleAI API that reacts to incoming webhook events from your git provider. Here is a precise breakdown of each phase:
Phase 1 — Webhook Receipt
When a pushevent or a merged pull request is detected on your configured branch, your git provider (GitHub, GitLab, or Bitbucket) dispatches a signed HTTP POST to your project's unique ToggleAI webhook endpoint (e.g., https://api.toggleai.fun/git/webhooks). ToggleAI validates the HMAC-SHA256 signature in the X-Hub-Signature-256 header to confirm the payload is authentic and untampered.
Phase 2 — File Fetch & Parse
The engine uses the stored access token to fetch the latest .toggleai/flags.yaml at the exact commit SHA referenced in the webhook payload. The YAML is parsed and validated against the ToggleAI config schema. Unknown fields emit a warning; structurally invalid documents abort the sync and trigger an error notification.
Phase 3 — Diff & Change Detection
The engine computes a diff between the parsed YAML state and the current configuration stored in the ToggleAI database. Only changed flags and configs are updated — unchanged entities are untouched — making syncs efficient and reducing database churn for large flag sets.
Phase 4 — Database Write & Cache Invalidation
Validated changes are committed to the primary database in a single atomic transaction. Immediately after, the edge cache TTLs for affected flags are invalidated so that SDK clients receive updated evaluations on the next polling cycle or SSE push — with no additional manual intervention.
Phase 5 — Sync Status & Audit Log
A sync event entry (including commit SHA, timestamp, changed entities, and status) is appended to the project audit log. The GitOps dashboard in the console reflects the latest sync state, including any validation warnings or conflict tickets needing manual resolution.
The following diagram illustrates the complete end-to-end journey of a config change — from a developer commit in a local branch to live SDK evaluation at the edge.
Step 1: Connect Repository
Navigate to the project settings in the ToggleAI console under Git Connections and select your provider (GitHub, GitLab, or Bitbucket). Provide a fine-grained access token with read access to repository Contents and read/write access to Webhooks (required for bidirectional sync). The token is encrypted at rest using AES-256.
Step 2: Add Configuration File
Create a file named .toggleai/flags.yaml at the root of your repository. This file is the single source of truth for your flag states, targeting rules, and remote config values. You can scaffold the initial file from your existing flags using the ToggleAI CLI:
toggleai flags export --format yaml > .toggleai/flags.yamlStep 3: Configure Webhook
ToggleAI provides a unique webhook payload URL visible in the Git Connections dashboard. Register it in your repository webhook settings:
- Payload URL:
https://api.toggleai.fun/git/webhooks/{project-id} - Content type:
application/json - Events:
PushandPull Request (merged) - Secret: Copy the HMAC secret from the console and paste it into the webhook secret field
Step 4: Select Sync Direction
Choose your synchronization direction in the connection settings. We recommend Git-only for teams adopting Flags-as-Code for the first time to establish a clean one-way source of truth before enabling bidirectional sync.
The .toggleai/flags.yaml file uses a structured schema with two top-level sections: flags for boolean/string/number/json feature flags, and configs for typed remote configuration values.
Top-Level Fields
| Field | Type | Required | Description |
|---|---|---|---|
| version | integer | ✅ Yes | Schema version. Currently must be 1. |
| project | string | ✅ Yes | Your ToggleAI project ID as shown in console settings (e.g. proj_prod_billing). |
| flags | map | ⬜ Optional | Map of flag keys to flag definition objects. Keys must be lowercase kebab-case. |
| configs | map | ⬜ Optional | Map of config keys to remote config definition objects. At least one of flags or configs is expected. |
Flag Definition Fields (flags.*)
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | ✅ Yes | Human-readable display name shown in the console dashboard. |
| type | enum | ✅ Yes | Value type: boolean, string, number, or json. |
| description | string | ⬜ Optional | Plain-text description of the flag's purpose. Displayed in the console and included in audit log entries. |
| tags | string[] | ⬜ Optional | Labels for filtering and organizing flags (e.g. [billing, experiment]). |
| permanent | boolean | ⬜ Optional | When true, the Lifecycle Manager never marks this flag as stale. Use for kill switches and ops controls. |
| environments | map | ✅ Yes | Environment-specific targeting rules. Keys must match environment slugs in your ToggleAI project (e.g. production, staging). |
| variations | object[] | ⬜ Optional | Named variants for A/B tests and multivariate experiments. Each has a key and a typed value. |
| targeting_rules | object[] | ⬜ Optional | Ordered list of targeting rules evaluated top-to-bottom. Each rule includes conditions and a serve variant or value. First match wins. |
Environment Object Fields (flags.*.environments.*)
| Field | Type | Description |
|---|---|---|
| enabled | boolean | Master on/off switch. When false, all evaluations return the default value regardless of targeting rules. |
| rollout_percentage | integer (0–100) | Percentage of users who receive the 'on' value. Uses deterministic hashing on user ID for consistent bucketing. |
| default_value | any | Value returned when a user is outside the rollout bucket or no targeting rule matches. |
Targeting Rule Operators
Each condition in a targeting rule uses one of the following operators to match user attributes passed in the evaluation context:
| Operator | Description | Example |
|---|---|---|
| equals | Exact match (string or number) | plan equals "premium" |
| not_equals | Does not match | region not_equals "eu" |
| contains | Substring match (strings only) | email contains "beta" |
| ends_with | String ends with value | email ends_with "@acme.com" |
| starts_with | String starts with value | userId starts_with "usr_beta_" |
| in | Attribute value is in a list | country in [US, CA, GB] |
| not_in | Attribute value is NOT in a list | plan not_in [free, trial] |
| regex | Attribute matches a regular expression | userId regex "^usr_[0-9]+$" |
| greater_than | Numeric comparison (greater than) | account_age_days greater_than 30 |
| less_than | Numeric comparison (less than) | usage_mb less_than 500 |
Full Annotated Example
# .toggleai/flags.yaml
version: 1 # Schema version — always 1 for now
project: "proj_prod_billing" # Your ToggleAI project ID
flags:
new-billing-dashboard: # Flag key — lowercase kebab-case
name: "New Billing Dashboard" # Display name shown in console
type: boolean # Type: boolean | string | number | json
description: "Enables the redesigned billing dashboard for eligible users."
tags: [billing, dashboard] # Searchable labels in the console
permanent: true # Never auto-archived by Lifecycle Manager
environments:
production:
enabled: true # Master switch — false means flag is entirely off
rollout_percentage: 50 # Serve 'on' value to 50% of users (deterministic hash)
default_value: false # Returned for users outside the rollout bucket
staging:
enabled: true
rollout_percentage: 100 # All staging users get the flag
default_value: false
variations: # Optional: named variants for A/B tests
- key: control # Variant key — referenced in targeting_rules.serve
value: false
- key: treatment
value: true
targeting_rules: # Ordered rules — first match wins
- description: "Internal employees always get treatment"
conditions:
- attribute: email # User attribute key in the evaluation context
operator: ends_with # See operator table above
value: "@acme.com"
serve: treatment # Variant key or a literal typed value
- description: "Premium users get early access"
conditions:
- attribute: plan
operator: equals
value: "premium"
serve: treatment
dark-mode-toggle:
name: "Dark Mode"
type: boolean
tags: [ui, experiment]
environments:
production:
enabled: true
rollout_percentage: 25
default_value: false
staging:
enabled: true
rollout_percentage: 100
default_value: false
configs:
max-checkout-limit: # Config key — lowercase kebab-case
type: number # Type: string | number | boolean | json
description: "Maximum items allowed in a single checkout session."
environments:
production:
value: 100 # Resolved value returned by the SDK
staging:
value: 10
checkout-api-endpoint:
type: string
environments:
production:
value: "https://api.acme.com/v3/checkout"
staging:
value: "https://staging-api.acme.com/v3/checkout"
feature-limits:
type: json # JSON configs can hold complex structured data
environments:
production:
value:
max_items: 50
allow_bundles: true
rate_limit_rps: 100ToggleAI supports three distinct synchronization directions configured per-project. Choose the mode that matches your team's workflow:
Git → ToggleAI (Git-only, Recommended)
Commits to your configured branch are the only way to change flag configurations. The console becomes read-only — all edits must go through a pull request. This is the most auditable and conflict-free mode, recommended for regulated industries and large teams.
ToggleAI → Git (Console-only)
Changes made in the ToggleAI console are automatically committed and pushed to the connected branch. The YAML file stays up to date as a git-backed audit trail, but the console remains the primary interface. Useful for teams gradually migrating to Flags-as-Code.
Bidirectional Sync
Changes from both Git pushes and console edits are synchronized. Non-conflicting changes are resolved automatically. When the same flag is modified in both Git and the console simultaneously, ToggleAI pauses auto-sync for that flag and creates a Conflict Ticket requiring manual resolution.
The GitOps Engine runs multiple validation layers before deploying any config change to protect production workloads:
Schema Validation
Every incoming YAML document is validated against the ToggleAI JSON Schema. Fields with incorrect types, unsupported operators, or missing required keys are rejected with a detailed error referencing the exact field path (e.g., flags.new-billing-dashboard.type).
CI Dry-Run via ToggleAI CLI
Add the following GitHub Actions workflow to validate pull requests before merging:
# .github/workflows/toggleai-validate.yml
name: Validate ToggleAI Config
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ToggleAI CLI
run: npm install -g @toggleai/cli
- name: Validate flags.yaml
run: toggleai flags validate .toggleai/flags.yaml
env:
TOGGLEAI_API_KEY: ${{ secrets.TOGGLEAI_API_KEY }}Rollback via Git Revert
Because the YAML file is versioned in git, rolling back a bad flag change requires only a git revert. When the revert is pushed, ToggleAI's webhook handler re-processes the file and restores the previous configuration atomically — no manual intervention required.
# Roll back the last commit to .toggleai/flags.yaml
git revert HEAD --no-edit
git push origin main