Scheduling and Billing

How GitHub Schedules and Bills a Job's Minutes

When a run starts, each job whose needs are met becomes a request for a runner with matching labels. Independent jobs queue together, which is why both BookNest jobs started in the same second. A job waiting 24 hours for a runner is cancelled; a job may run 6 hours on a hosted runner (5 days self-hosted), and a run 35 days. The Free plan runs 20 standard jobs at once, Pro 40 and Team 60.

Where each job ran, and what GitHub countedShell
gh api repos/{owner}/{repo}/actions/runs/36127936652/jobs \
  --jq '.jobs[] | "\(.name) on \(.labels[0]): \(.started_at[11:19]) to \(.completed_at[11:19])"'
gh api repos/{owner}/{repo}/actions/runs/36127936652/timing \
  --jq '{billable_ms: .billable.UBUNTU.total_ms, jobs: .billable.UBUNTU.jobs,
         run_ms: .run_duration_ms}'
Output
in-a-container on ubuntu-24.04: 11:10:30 to 11:10:39
on-the-runner on ubuntu-24.04: 11:10:30 to 11:10:34
{"billable_ms":0,"jobs":2,"run_ms":19000}

Billing is per job: GitHub 29 rounds each job up to a whole minute and applies the runner's rate. Standard hosted runners are free for public repositories, hence 0 ms. In a private repository these jobs would use 2 of the plan's included minutes (2,000 a month on Free, 3,000 on Pro and Team); beyond them, Linux costs $0.006 a minute, Windows $0.010 and macOS $0.062. Self-hosted runners are free. The timing endpoint is being closed down; Self-Hosted and Pricing estimates BookNest's bill from the billing reports.