Actions cost allocation

The invoice says minutes. Your teams need dollars.

Short answer

GitHub Actions cost allocation means mapping billed minutes back through the chain that produced them: job to workflow, workflow to repository, repository to team, team to cost center. GitHub bills Actions at the account level, so none of that mapping exists on the invoice. Building it is what turns a shared platform cost into an owned one.

Why the invoice can't allocate itself

Actions consumption is metered per minute and billed to the organization or enterprise. The invoice knows the total. It does not know that 40% of it came from one integration test suite in one repository owned by one team, because ownership is not a billing concept in GitHub.

That is not an oversight — it is how a shared platform bills. But it means allocation is something you construct from usage data, and the quality of your allocation is the quality of your repository-to-team mapping. Get that mapping wrong and every downstream number is wrong in a way that is very hard to spot.

The allocation chain

Four hops, each of which can break:

Job → workflow
Available directly from run data. This is the only hop GitHub gives you cleanly.
Workflow → repository
Also direct. Together these two answer 'which pipelines are expensive', which is where most optimisation work starts.
Repository → team
The hop that breaks. Needs an ownership map that is maintained, not inferred from who last committed. Repos with no owner are the single biggest source of unallocated cost.
Team → cost center
A finance mapping, usually stable, usually maintained outside GitHub entirely. Worth keeping in one place so allocation and chargeback agree.

Runner multipliers change the answer

Minutes are not fungible. GitHub-hosted runners bill at different rates by operating system, so a Windows or macOS minute costs a multiple of a Linux one. Larger runners bill at their own per-minute rate and typically come with no included allowance at all.

Allocating raw minute counts therefore misattributes cost systematically: the team running a small Linux matrix looks expensive next to the team running a handful of macOS builds, when the reverse is true in dollars. Allocate cost, not minutes — apply the rate at the job level before you aggregate.

Shared, ambiguous, and monorepo cases

Every allocation model meets three awkward cases. Shared infrastructure repos — the deploy pipeline everyone triggers. Monorepos, where one repository is genuinely owned by six teams. Orphans, where the owner left and nobody claimed it.

The honest answer is to allocate what you can cleanly and leave the rest visible as unallocated rather than smearing it across teams with a formula nobody agreed to. An unallocated bucket that shrinks quarter over quarter is a healthy signal. A tidy allocation built on an invented split rule is a number your teams will dispute the first time it costs them something.

Showback before chargeback

Showback is publishing each team's number. Chargeback is moving it onto their budget. Skipping straight to chargeback is the classic way to kill an allocation programme, because the first month's numbers will be wrong, and the argument that follows will be about your methodology rather than their pipelines.

Run showback until teams stop disputing the numbers. That usually takes a quarter, and the disputes themselves are how the ownership map gets fixed.

FAQ

Frequently asked questions

Can GitHub show Actions cost per team?

Not natively. Actions minutes are metered per job and billed at the organization or enterprise level, with no team dimension on the invoice. Per-team cost has to be constructed by mapping jobs to repositories and repositories to owning teams, then applying each runner's rate before aggregating.

Should we allocate Actions minutes or Actions cost?

Cost. Runner minutes bill at different rates by operating system and runner size, so a team running macOS builds can consume far fewer minutes than a team running Linux matrices while costing considerably more. Aggregating raw minutes misattributes spend systematically in favour of the expensive runners.

How do we handle monorepos and shared pipelines?

Leave them visible as unallocated rather than splitting them with a rule nobody agreed to. A clearly labelled unallocated bucket that shrinks over time is more credible than a complete allocation built on an invented formula — and teams will accept a chargeback far more readily when the shared portion is stated openly.

What's the difference between showback and chargeback?

Showback publishes each team's cost without moving money; chargeback transfers it onto their budget. Run showback first, for at least a quarter. The early numbers will be wrong because repository ownership maps are always stale, and disputes during showback are how that map gets fixed before real money depends on it.

Try it

See these numbers for your own org

Connect your organization read-only and FinOpsAid meters it nightly — seats, credits, minutes, Codespaces and storage, attributed to teams and reconciled against your billing API. Every modeled figure is labelled an estimate, with the date it was computed.