Can I Run More Jobs Than My Plan Allows?
Yes. The concurrent job ceiling on your GitHub plan counts jobs on GitHub-hosted labels only, so jobs routed to warp- labels queue on WarpBuild capacity.
Answer
Yes, because the concurrent job ceiling attached to your GitHub plan counts jobs running on GitHub-hosted runners, and it stops counting at the point where a job is dispatched somewhere else. That ceiling runs from 20 concurrent jobs on Free to 500 on Enterprise with a lower macOS sub-ceiling, per GitHub's usage limits reference, checked on 2026-08-13; a job whose runs-on value resolves to a warp- label is handed to a WarpBuild runner and queues on WarpBuild capacity instead.
The boundary is drawn per job, by the runs-on value on that job. There is no account setting and no plan upgrade involved. Two jobs in the same workflow file can sit on opposite sides of it.
| Where the job runs | Draws from the GitHub plan ceiling | What decides when it starts |
|---|---|---|
ubuntu-latest, windows-latest, macos-latest and other GitHub-hosted labels | Yes | Free slots under your plan ceiling |
warp- labels | No | WarpBuild pool capacity for that label |
| Self-hosted labels you register yourself | No | Count of matching runners you keep online |
Per the cloud runners documentation. Run as many jobs as your workflows need. Generally available Linux and Windows runners do not have plan-level concurrency caps. That statement carries the scope written in the same documentation: features that are Generally Available support unlimited concurrency on Linux and Windows runners, and features in beta may carry limits. macOS runs on a per-organization quota, so teams that need high macOS concurrency arrange it with support at [email protected]. Slack support channels are also available on demand, per the pricing page.
Detail
Move the fan-out, keep the rest
Routing per job means the migration is a label change on the jobs that fan out. The workflow below keeps a single lint job on the GitHub-hosted pool and sends a 40-way integration matrix to warp-ubuntu-latest-x64-4x, so exactly one job in this file draws from the plan ceiling.
name: integration
on:
pull_request:
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run lint
integration:
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
suite: [api, web, worker, jobs]
runs-on: warp-ubuntu-latest-x64-4x
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm run test:${{ matrix.suite }} -- --shard=${{ matrix.shard }}/10The matrix produces 10 shards by 4 suites, so 40 jobs are eligible to start together. On a Free-plan account with a 20-job ceiling, the same 40 jobs on ubuntu-latest would run in two waves. Nothing else in the file changes: the same steps, the same actions, the same Node version.
Limits that survive the move
Three limits belong to the repository or the workflow rather than to the runner, and they hold after the labels change. All three were checked on 2026-08-13 against GitHub's usage limits reference.
- 256 jobs per matrix per workflow run. The matrix above sits at 40. Past 256, split the suite across workflows or collapse a dimension.
- The
concurrencykey you wrote. A group holds one running item and one pending item regardless of which runner the work lands on. The guide to GitHub Actions concurrency limits covers the group shapes that serialize a workflow by accident. - 24 hours of queue time. A job waiting on a self-hosted or managed runner is dropped after 24 hours.
A fourth failure mode looks like a capacity problem and is a routing problem: a job whose labels match zero online runners waits without logs. Check the label spelling and the runner group permissions in the common issues documentation before you conclude that a pool is full.
What the extra parallelism costs
Assume the 40 integration jobs above each take 5 minutes, with no retries. Total compute is 200 job-minutes per run whether those jobs run in one wave or two, so the fan-out buys back wall clock and leaves billed minutes alone.
| Slots available | Waves | Wall clock per run | Billed job-minutes |
|---|---|---|---|
| 20 | 2 | 10 min | 200 |
| 40 | 1 | 5 min | 200 |
Priced at the catalog rate for warp-ubuntu-latest-x64-4x, 200 minutes at $0.008 per minute is $1.60 per run. At 300 pull request runs a month that is 60,000 job-minutes and $480.00, and the second row returns 5 minutes of wall clock on every one of those runs.
| runs-on label | vCPU | RAM | Rate per minute |
|---|---|---|---|
| warp-ubuntu-latest-x64-2x | 2 | 8GB | $0.004 |
| warp-ubuntu-latest-x64-4x | 4 | 16GB | $0.008 |
| warp-ubuntu-latest-arm64-4x | 4 | 16GB | $0.006 |
| warp-windows-latest-x64-4x | 4 | 16GB | $0.016 |
| warp-macos-latest-arm64-6x | 6 | 22GB | $0.080 |
Full per-minute rates by runner type are on the pricing page.
Confirm the ceiling moved
Measure queue wait per runner label before and after the label change rather than reading the running job count alone. A label whose P90 queue wait stays flat while the number of jobs running together climbs past the old plan ceiling is the signal that the ceiling stopped binding. A P90 that climbs on one label while other labels start on time points at capacity for that label. The guide to GitHub Actions queue times walks through each reading and the fix that matches it.
Related Questions
Which jobs count against my GitHub plan ceiling?
Jobs whose runs-on resolves to a GitHub-hosted label such as ubuntu-latest, windows-latest, or macos-latest. The ceiling runs from 20 concurrent jobs on Free to 500 on Enterprise, checked on 2026-08-13 against GitHub's usage limits reference. Jobs that target warp- labels are dispatched to WarpBuild runners and queue on WarpBuild capacity instead. The full breakdown of every ceiling between a queued job and a running one is in how many GitHub Actions jobs can run at once.
Do I have to move every job to raise the ceiling?
No. Routing is per job, so a workflow can keep a small lint job on ubuntu-latest and send a 40-way test matrix to warp-ubuntu-latest-x64-4x. Only the jobs still on GitHub-hosted labels draw from the plan ceiling after that, which makes the migration reversible one job at a time.
Which limits still apply after the move?
Repository-level limits stay in force. A matrix still generates at most 256 jobs per workflow run, your concurrency key still throttles the groups you named, and a job queued for a self-hosted or managed runner is dropped after 24 hours. The guide to GitHub Actions concurrency limits maps each of those to the symptom it produces.
Price your own fan-out against the per-minute rates on the pricing page, then change the runs-on value on one matrix job and watch where the queue moves.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.