Picture a pull request that changes one line of azure-pipelines.yml. The build logic is untouched; only the vmImage value moves from a stock label to windows-2025-vs2026-16-core. Your reviewer approves it in seconds, because why wouldn't they? With this release that line is a purchasing decision. Microsoft has made GitHub-hosted agents with pay-as-you-go pricing generally available in Azure Pipelines, and the per-minute rate now depends on the label your YAML asks for.
What shipped, and what is still preview
Per the Azure DevOps Blog, the agents and pay-as-you-go pricing are generally available, as are the macOS agent SKUs. The Linux and Windows agent SKUs are in public preview.
The new pool is called GitHub-hosted Agents. It sits beside the existing Microsoft-hosted Azure Pipelines pool and runs on the same infrastructure as GitHub Actions, in the same regions as Microsoft-hosted agents. Each job gets a fresh, isolated virtual machine that hosts a single agent and is reimaged after the job finishes.
| OS | SKU | Rate per minute | vCPU / RAM | Architecture |
|---|---|---|---|---|
| macOS | Standard | $0.062 | 3 / 7 GB | arm64 (M1) |
| macOS | XLarge | $0.102 | 5 plus 8 GPU cores / 14 GB | arm64 (M2) |
| Linux | 8-core | $0.022 | 8 / 32 GB | x64 |
| Linux | 16-core | $0.042 | 16 / 64 GB | x64 |
| Windows | 8-core | $0.042 | 8 / 32 GB | x64 |
| Windows | 16-core | $0.082 | 16 / 64 GB | x64 |
Why would a security person read a price list?
The first reason is good news, so let's take it first. One VM per job, reimaged afterwards, is the isolation model we keep nagging teams to adopt. A long-lived agent builds up state: a token left in a config file, a workspace someone forgot to clean, a tool cache that yesterday's job tampered with. A VM that is thrown away after one job leaves none of that behind. Now you get that on Apple silicon and on big Linux and Windows boxes without running the fleet yourself. Credit where due.
The second reason is the billing model. Under parallel-job billing, your brake was the concurrency you had bought in advance. Run out of slots and jobs simply queued. In the new pool you don't need to buy parallel-job capacity for it, its jobs don't consume your existing parallel jobs, and Microsoft spells it out plainly: "There is no free tier or allocation of free minutes for GitHub-hosted agents."
So the old brake doesn't apply here, and the spending decision now sits in a YAML field anyone with write access can edit. Run the published rates and an hour costs $1.32 on 8-core Linux, $4.92 on 16-core Windows and $6.12 on XLarge macOS. Small numbers. Then a matrix fans out, a flaky test triggers retries, and they stop being small. Give pool: changes the same review as a dependency bump, because each one now carries a cost.
Turning it on, pipeline by pipeline
You need permission to configure your organization's billing settings. Then go to Organization settings > Billing, set Enable GitHub-hosted agents to On, and save. Azure DevOps provisions the new pool, which can take up to 24 hours. Turning it on doesn't change existing pipelines or start any jobs. Pipelines stay on their current pool until you edit them, and charges begin only when a job actually runs on a GitHub-hosted agent.
To move a pipeline, name the pool and pick an image label:
pool:
name: 'GitHub-hosted Agents'
vmImage: 'ubuntu-24.04-8-core'
Usage shows up on the pool's Analytics tab, which you can filter by agent SKU, project and pipeline. It also lands in Azure Cost Management, where you can filter by organization and project and set budgets and alerts. Set the alert before the first job runs. The first invoice is a bad place to learn the rates.
Fine print worth a second read
- Watch the copy-paste. The blog post introduces its macOS YAML example as a standard macOS agent, but the snippet uses
xcode-27-xlarge. In the post's own table that label belongs to the XLarge SKU at $0.102 a minute. The Standard labels aremacos-26-arm64andxcode-27. - Linux and Windows SKUs are still preview, and not every label is available everywhere yet. The
ubuntu-26.04-8-core,ubuntu-26.04-16-core,windows-2025-8-coreandwindows-2025-16-coreimages are still rolling out to organizations. The Ubuntu 24.04 images and the Windows Server 2025 with Visual Studio 2026 images are available to every organization that has enabled the pool. - The jobs run on GitHub Actions infrastructure. If your compliance paperwork says where builds execute, update it; the regions match Microsoft-hosted agents.
How the rest of hosted CI charges for the same minute
The other big hosted platforms already bill this way. GitHub Actions bills hosted runner time by the minute, and its larger runners are charged per minute as well. GitLab.com counts compute minutes and weights bigger machine types with cost factors. CircleCI sells credits that are used up per minute at a rate set by resource class. Bitbucket Pipelines counts build minutes, and larger step sizes use them up faster. Self-hosted agents skip the per-minute bill on every one of them, and in exchange the cleanup between jobs becomes your problem.
My verdict: switch, especially for Apple builds, because a fresh VM per job beats a long-lived Mac mini that nobody ever reimages. But put a required reviewer on the pipeline file first. The VM forgets everything after each job. Your invoice won't.
Top comments (1)
The closing line is right, and I'd push on the control you recommend, because I don't think it covers the risk you've correctly identified.
A required reviewer on the pipeline file protects the pipeline file. The spend isn't always in it. If vmImage reads from a variable, that variable can be changed in the pipeline UI with no pull request and no movement in the YAML. If the pool comes from a template in another repo, changing that repo changes the SKU for every pipeline consuming it. And a matrix can fan out from a variable while the file stays byte-identical.
So the review catches the obvious version and misses the three that never touch the file.
The bigger thing is what happened to the brake. Under parallel-job billing the limit was preventive and hard. Slots ran out, jobs queued, nothing was spent. What you're recommending in its place is a budget alert, which is a detective control. It fires after the money is gone, and cost data lags, so a runaway matrix with retries can burn through an afternoon before anyone's phone buzzes.
That isn't an argument against the move, which I agree with, especially for Apple builds. It's an argument that the brake was removed and not replaced. Those are different sentences, and the second one is what a finance team needs to see.
Your catch on Microsoft's own macOS example is the detail I'd put in front of anyone enabling this. A docs snippet labelled standard that uses an XLarge label is exactly the sort of thing that gets copied once and then runs for a year.