The short answer: GitHub does not sell a feature flag product. There is no flag dashboard, no targeting engine and no runtime evaluation API anywhere in GitHub or GitHub Actions. What people find when they search for GitHub feature flags is one of four different things: if: conditionals in workflows, Actions configuration variables, deployment environments with protection rules, or articles about the flag system GitHub built for itself and never shipped. The first three gate your pipeline. None of them can turn a feature on for 5% of your users without a new commit and a new deployment.
That distinction is the whole article, and it is worth being precise about, because the two things fail in completely different ways.
The four things people mean
Search results for this term mix these together constantly. They are not interchangeable.
| What it is | What it can gate | Runtime user targeting? |
|---|---|---|
if: conditionals in a workflow | Whether a job or step runs, based on branch, event, actor or an expression | No |
| Actions configuration variables | Non-secret values read as ${{ vars.NAME }}, settable at repository, organization or environment level | No |
| Deployment environments | Which environment a deploy targets, plus required reviewers and wait timers | No |
| GitHub's internal flag system | Everything, for GitHub. It is not a product you can buy. | Yes, but not for you |
The first three are real and useful. If your goal is "do not run the expensive integration suite on documentation-only pull requests" or "require two approvals before this workflow can deploy to production", GitHub already does that well and you should not add a vendor for it.
What Actions variables genuinely do
Configuration variables are the closest thing GitHub has to a flag store. They hold non-secret values and can be defined at three scopes: repository, organization, and environment. Workflows read them through the vars context.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy the new billing service
# Only runs when someone set NEW_BILLING to 'true' in repo settings.
if: ${{ vars.NEW_BILLING == 'true' }}
run: ./deploy.sh billing
Two properties matter here. Environment-scoped variables mean the same workflow can behave differently for staging and production without duplicating YAML, which is genuinely handy. And because if: conditionals are not sent to the runner, you must read variables through contexts rather than shell syntax there. That trips people up constantly.
The ceiling arrives quickly though. Changing a variable does nothing until a workflow runs again. So a "flag flip" is really: edit a setting, then trigger a pipeline, then wait for a build and a deploy. If your deploy takes eight minutes, your fastest possible rollback is eight minutes. That is a very different guarantee from a kill switch that takes effect in seconds without shipping anything, and the gap is exactly what you feel at 2am. Even with a well-tuned pipeline and zero-downtime deployments, you are still bounded by build time, because the decision lives in your artifact rather than in your runtime.
The line where this stops working
Build-time configuration and runtime flags solve different problems. Here is the honest split.
| You want to... | GitHub alone | Needs a runtime flag |
|---|---|---|
| Skip a slow test job on doc changes | Yes, cleanly | No |
| Require approval before a production deploy | Yes, environment protection rules | No |
| Turn a feature on for internal staff only | No | Yes |
| Roll a feature to 1%, then 10%, then everyone | No | Yes |
| Turn a broken feature off in ten seconds | No, requires a redeploy | Yes |
| Run an A/B test with consistent bucketing | No | Yes |
| Enable a feature for one enterprise customer | No | Yes |
| Merge unfinished code to main safely | No | Yes |
That last row is the one that catches teams. If you are moving toward trunk based development, where work merges to main daily and main stays releasable, a workflow conditional cannot help you. The unfinished code is already in the artifact. Something has to decide at request time whether a given user sees it, and GitHub has no component that does that.
GitHub built this for itself and did not ship it
The genuinely interesting part of this topic is that GitHub is one of the most committed feature flag users in the industry. Their engineering blog describes the system in detail, and it reads like a product spec for a commercial flag platform.
Flags are administered through a web UI that most engineers have access to, though not all staff. Each flag carries a history of changes: who changed it, when, what changed, and which team owns it. Flags can be applied to users, organizations, teams, enterprises, repositories or GitHub Apps, which is a richer actor model than several paid products offer. Rollouts go to individual actors first, then to staff, then to a percentage of actors, and when that percentage changes a message is posted automatically to their deployments channel in Slack. They also dark ship, enabling a change for a percentage of calls rather than users, to test internal behavior with no user-visible effect.
Performance got real attention too. Flag metadata is cached in memcached, though large flags like the GitHub Actions rollout, which scaled to tens of thousands of users a week, still required per-actor MySQL queries.
The detail I find most telling is cleanup. GitHub wrote a script using git grep and rubocop-ast that removes a retired flag's dead code branches, reindents what is left, creates a branch and opens a pull request. Nobody automates flag deletion unless flag debt has become a genuine engineering cost. It is the strongest available evidence that the cleanup discipline in our feature flag best practices guide is not theoretical.
GitHub has open-sourced adjacent tooling, most notably Scientist, a Ruby library for refactoring critical paths by running the old code as a control and the new code as a candidate in randomized order, returning only the control's result while recording mismatches. That is a rigorous pattern and worth knowing. It is not, however, a flag management system, and it does not give you a dashboard, targeting or a rollout percentage.
Wiring real flags into GitHub Actions
If you do want a workflow to react to a flag that a product manager can flip without a commit, the pattern is to evaluate the flag over the network inside the job rather than reading a repository setting.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- id: flag
run: |
value=$(curl -sf \
-H "Authorization: Bearer $TOGGLED_KEY" \
"https://api.toggled.ai/v1/flags/deploy-billing-v2?env=production" \
| jq -r '.enabled')
echo "enabled=$value" >> "$GITHUB_OUTPUT"
env:
TOGGLED_KEY: ${{ secrets.TOGGLED_KEY }}
- if: steps.flag.outputs.enabled == 'true'
run: ./deploy.sh billing
Set a default in the script for the case where the call fails, so a flag service outage does not silently change what your pipeline deploys. Defaulting to the old, known-good path is almost always right.
Worth noting for comparison: GitLab took the opposite approach and ships flags as part of the platform, including on its free tier with a 50-flag-per-project limit. If you assumed the two platforms were equivalent here, they are not, and we covered what GitLab includes in our write-up on GitLab feature flags.
Questions people actually ask
Does GitHub have feature flags?
Not as a product. GitHub offers no flag dashboard, no targeting rules and no runtime evaluation API. It offers workflow conditionals, configuration variables and deployment environments, which gate your CI/CD pipeline rather than your application's behavior for a given user. GitHub does run an extensive internal flag system, but it has never been released for customers to use.
How do I use feature flags in GitHub Actions?
For static, pipeline-level control, define a configuration variable at repository, organization or environment scope and check it in an if: conditional using ${{ vars.NAME }}. For dynamic control that someone can change without editing YAML or re-running a workflow, call a flag provider's API inside a step, write the result to $GITHUB_OUTPUT, and condition later steps on that output.
What is the difference between a GitHub Actions variable and a feature flag?
A variable is read when a workflow runs and affects what gets built or deployed. A feature flag is read when your application handles a request and affects what a specific user sees. Changing a variable requires a pipeline run to take effect; changing a flag takes effect immediately, for everyone or for a targeted slice. We compared this trade-off in depth in feature flags vs environment variables.
Can I use GitHub as a feature flag backend?
People do try, usually by committing a JSON file and reading it from a raw content URL. It works until it does not. There is no targeting logic, no percentage bucketing, no audit trail beyond commit history, and raw content is cached, so propagation is neither immediate nor predictable. It also means a non-engineer cannot change a flag without a pull request, which removes most of the point.
Is GitHub Flow the same as feature flags?
No, and the similar names cause real confusion. GitHub Flow is a branching strategy: branch from main, open a pull request, merge back to main. Feature flags are a runtime mechanism for controlling who sees a change. They are complementary, and in practice any branching model with short-lived branches needs flags to handle work that takes longer than a branch should live.
The practical takeaway
Use GitHub for what it is good at. Workflow conditionals and environment protection rules are a clean way to control your pipeline, and reaching for a third-party tool to decide whether a test job should run is overkill.
But be clear-eyed about the boundary. The moment the question becomes "which users see this" rather than "does this job run", GitHub has nothing for you, and the workaround of committing a config change and waiting for a deploy is not a substitute. It is worth remembering that GitHub reached the same conclusion internally and built a full flag platform with actor targeting, percentage rollouts, ownership metadata and automated cleanup. They just did not sell it.
If you are choosing what to put in that gap, our comparison of the best feature flag tools covers what each vendor charges and where each one stops, and the concept itself is explained from scratch in our guide to the feature toggle.