← Back to Blog

FUNDING.yml alone won't show a Sponsor button: notes from auditing 42 repos

Yesterday I published three OSS repositories and thought the sponsorship plumbing was done. My account-wide FUNDING.yml was inherited, and querying the API returned the funding links just fine. Then I opened the repo pages: no Sponsor button anywhere.

The API said “it’s there”; the page said “it isn’t.” The cause turned out to be a two-layer design in GitHub, and one of the layers only bites people who create repos from the CLI. I ended up auditing all 42 of my public repositories, so here are the notes.

The Sponsor button is a two-layer system

The button only renders when two independent settings are both in place.

LayerWhat it doesWhere it lives
FUNDING.ymlWhat to show (the list of links).github/FUNDING.yml
Sponsorships flagWhether to show it at allRepo Settings → Features checkbox

For FUNDING.yml, one file in a repository named .github becomes the default for every public repo in the account. Mine lists GitHub Sponsors and Ko-fi, and it was inheriting into new repos exactly as documented.

The other layer is the trap. Creating FUNDING.yml through the web UI turns the flag on for you. Creating the repo with gh repo create or a plain git push leaves the flag off. Browser users never learn the flag exists; CLI users trip over it silently.

And this flag is not in the REST API at all. It only exists in GraphQL as hasSponsorshipsEnabled, which is why you won’t find it among the gh repo edit options. Enabling it looks like this:

id=$(gh api graphql -f query='{ repository(owner: "you", name: "repo") { id } }' \
  --jq '.data.repository.id')

gh api graphql -f query='
mutation($id: ID!) {
  updateRepository(input: {repositoryId: $id, hasSponsorshipsEnabled: true}) {
    repository { name hasSponsorshipsEnabled }
  }
}' -f id="$id"

“The API returns it” and “it’s displayed” are different claims

That was my mistake at the start. GraphQL returned both funding links, so I reported the button as live. What the response actually proves is that FUNDING.yml is inherited — nothing more. The button has its own switch.

The reliable check is to ask the rendered page:

curl -s "https://github.com/you/repo" | grep -c "Sponsor this project"
# 1 means the sidebar section is rendering

What auditing 42 repositories turned up

Suspecting more of the same, I swept every public repo on my account.

StateReposAction
Button showing12(3 of them fixed that same morning)
Active repos of mine, flag off9Enabled via GraphQL
Archived18Left alone
Forks3Left alone

All 12 of the showing buttons were hand-fixed: 3 that morning, 9 the day before. In other words, the number of repos where the button appeared on its own was 0 out of 42. The audit surfaced a second problem too: nine repos still carried per-repo FUNDING.yml files from an earlier setup pass, and eight of those were stale — GitHub Sponsors only, no Ko-fi. A per-repo file overrides the account default, so those eight repos had been quietly hiding the Ko-fi link. I deleted all nine and consolidated on the single file in .github.

Copying FUNDING.yml into each repository is how the two-source problem starts. Update the default later and the stale per-repo copies keep winning forever.

The audit script for your own account is short:

OWNER=you
gh repo list "$OWNER" --visibility public --limit 200 --json name --jq '.[].name' |
while read -r name; do
  flag=$(gh api graphql -f query="{ repository(owner: \"$OWNER\", name: \"$name\") \
    { hasSponsorshipsEnabled } }" --jq '.data.repository.hasSponsorshipsEnabled')
  echo "$flag  $name"
done | sort

Every false line is a repo with no button.

What I decided not to touch

Flipping everything to true was not the goal.

The 18 archived repos are read-only, so the mutation fails anyway. Unarchiving would work, but I could not summon the ambition to solicit sponsorships on a ten-year-old Android sample.

The 3 forks I skipped on purpose. A fork inherits the upstream FUNDING.yml, which carries the original author’s sponsorship links. One of mine, a terminal app fork, still points at the connectbot maintainer’s GitHub Sponsors. Replacing that with my own button would mean collecting support on someone else’s work. The upstream settings stay as they are.

The dish is free; the missed chances accumulate quietly

To be honest about revenue: my Sponsors numbers are not worth reporting yet. But with no dish set out, zero is guaranteed. GitHub Sponsors charges no platform fee on individual sponsorships, and Ko-fi takes 0% on donations, so the total cost of being sponsorable is the five minutes of setup. If you ship OSS as an indie developer, this belongs in the same breath as creating the repository.

One confession to close. I had hit this exact trap the day before, on a different repository, and had written myself a note about the fix. The next day I shipped three new repos and missed it three times in a row. Memory doesn’t scale, so the flag mutation and the rendered-page check are now part of my repo-publishing checklist. This post is an extension of that checklist.