GitHub Actions too slow?
When a GHA run is slow, the hard part is knowing whether the job waited for capacity, ran on underpowered hardware, or repeated work the workflow could skip. The run timeline separates the three, and each cause has its own smallest useful fix.
Try StarSling runnersHow StarSling worksTopics covered: This guide covers how to tell whether a slow run is waiting in a queue, starved by runner hardware, or wasting work in the workflow, and which fix to try first.
Slow GitHub Actions has three common causes: jobs wait before a runner starts, the runner hardware cannot finish the work quickly, or the workflow repeats unnecessary work. Measure total pre-start delay from the workflow run's created_at to each job's started_at. For jobs with needs dependencies, read the workflow at the run's head_sha and map each YAML job ID to its runtime rows, including matrix expansions. Only with an unambiguous mapping should you compare started_at with the latest upstream completed_at; otherwise report total pre-start delay without claiming a precise dependency-adjusted queue time. Then inspect checkout, install, build, test, and trigger timing before choosing a fix.
Real results
TL;DR
- Start with timestamps. Total pre-start delay is the gap from the workflow run's
created_atto the job'sstarted_at. For a job withneeds, read the workflow at the run'shead_shaand map YAML job IDs to every runtime row, including matrix expansions. Comparestarted_atwith the latest upstreamcompleted_atonly when that mapping is unambiguous; otherwise report total pre-start delay without claiming dependency-adjusted queue time. - If queue wait dominates, fix capacity and concurrency first. If execution dominates, test whether runner hardware or workflow waste is the long pole.
- Already know the runner is the limit? Go straight to Fast GitHub Actions. If not, diagnose first so you do not optimize the wrong stage.
- Not sure which check is the long pole? The /ci-speedup skill measures it for you.
Why are my GitHub Actions builds so slow?
GitHub Actions builds are usually slow because the job waits for runner capacity, the runner hardware is underpowered, or the workflow repeats work it could cache, skip, or parallelize. Use the run timeline as the routing table: the same slow PR can have more than one cause, but one usually dominates the developer wait.
| Cause | How to check | Best next fix |
|---|---|---|
| Queue wait before a runner starts | Fetch the workflow run and its jobs. Measure total pre-start delay as job started_at minus workflow-run created_at. The jobs response does not identify needs dependencies, so read the workflow file at the run's head_sha. Map each YAML job ID to its runtime rows, accounting for an explicit name and every matrix expansion. Only with an unambiguous mapping should you subtract the latest upstream job completed_at from its started_at; otherwise report total pre-start delay without claiming a precise dependency-adjusted queue time. | Read cut GitHub Actions queue time, scope concurrency per ref, cancel superseded PR runs, and use runner capacity that can absorb bursts. |
| Runner hardware is the limit | The job starts promptly, but CPU-heavy build, test, compression, or toolchain steps still take most of the wall-clock time. Rerun the same job on stronger Ubuntu hardware and compare the same step timings. | Use a faster Linux runner label and keep the workflow unchanged. The migration is a runs-on change; see Fast GitHub Actions. |
| Workflow waste repeats work | Checkout, dependency install, Docker build, monorepo build, or test steps dominate even when inputs barely changed. Look for missing caches, full-history checkout, one long test job, broad triggers, and obsolete steps. | Apply the matching best practice: cache dependencies, shallow checkout, build only affected projects, shard tests, or path filters. |
Start from the symptom you actually have
The table above routes by where the time goes. If you would rather start from what you can see, each of these pages takes one symptom, names its likely causes in the order worth checking, gives you the one check that confirms or rules out each cause, and links the page that carries the fix.
Every one of them also serves a plain .md version for coding agents, and the whole set is indexed at Diagnose a GitHub Actions problem.
- Why your test job is slower in CI than it is locally
- npm install or npm ci taking a large slice of every run
- pnpm install is slow in GitHub Actions
- Why is the Playwright job so slow in CI
- Why your Docker build rebuilds from scratch on every CI run
- A one-package change runs the whole monorepo's CI
- Why CI runs sit queued before any job starts
- Flaky tests: CI fails, then passes on an unchanged rerun
- A job hits a timeout, or hangs until GitHub kills it
- A GitHub Actions job stays queued or hangs with no output
- GitHub Actions cache reports a miss on every run
If hardware is the cause, the first test is one line
Keep GitHub Actions syntax and compare the same job on a supported StarSling Ubuntu runner. Move only Ubuntu/Linux jobs; leave macOS and Windows on GitHub-hosted runners.
runs-on: ubuntu-latestruns-on: starsling-ubuntu-24.04- Do not change steps during the first measurement, or you will not know what caused the delta.
- Compare the same job, on a similar commit, with the same cache warmth if possible.
- If the execution time barely moves, the bottleneck is probably workflow waste, networking, or an approval wait.
Workflow waste checks
When execution time dominates but hardware is not the whole answer, inspect the expensive stages in this order.
| Smell | Evidence in the run | Guide |
|---|---|---|
| Dependency install repeats from scratch | Package-manager install time is high on most PR runs, and setup actions show no cache hit tied to a lockfile. | Cache dependencies |
| Checkout pulls too much history | actions/checkout uses fetch-depth: 0 on jobs that only need the current tree. | Use shallow checkout |
| One test job is the long pole | The whole PR waits on one suite while other jobs finish early. | Shard tests |
| Docs-only changes run expensive suites | Workflow triggers do not distinguish source changes from unrelated files. | Path-filter guide for source-scoped workflows |
| Monorepo builds everything | A small package change starts builds and tests for projects the diff cannot affect. | Build only affected projects |
Paste this into your agent
This prompt asks for diagnosis before edits. That keeps the PR focused on the bottleneck instead of collecting unrelated CI tweaks.
Inspect the most recent slow GitHub Actions run and separate the wait before each job starts from the time the job spends executing steps. Pull the workflow run and its jobs from the Actions REST API. Report total pre-start delay as each job's started_at minus the workflow run's created_at. To adjust a job with needs dependencies, read the workflow file at the run's head_sha, then map each YAML job ID to its runtime job rows, accounting for an explicit name and every matrix expansion. Only when that mapping is unambiguous, compare the downstream started_at with the latest completed_at among every runtime row for its direct upstream jobs. Otherwise report total pre-start delay without claiming a precise dependency-adjusted queue time. Then group execution time by checkout, dependency install, build, tests, Docker, deploy, and fixed sleeps. Decide whether the dominant cause is dependency wait, runner queueing, runner hardware, or workflow waste. For each cause, propose the smallest safe fix, link it to the exact workflow lines, and say what measurement would prove the fix worked. Do not rewrite CI syntax or weaken required checks. Open one focused PR only if the evidence points to a clear fix.Public examples to inspect
The customer proof above is ratio-only and comes from published case studies. For public repository examples, inspect the diffs rather than the PR titles: these changes keep GitHub Actions and swap supported Ubuntu jobs to StarSling runner labels.
Use these as migration-shape examples, not as a promise that every workflow gets the same multiplier. Your timeline still decides whether queue wait, hardware, or workflow waste is the first fix.
When StarSling helps most
StarSling tends to help most when the diagnosis points to runner capacity, runner speed, or CI workflow waste in supported Ubuntu jobs.
- Your jobs already run on
ubuntu-latestorubuntu-24.04. - Queue wait or CPU-bound execution is visible in the run timeline.
- Install, checkout, test, or trigger waste can be turned into reviewable optimization PRs.
- You want to keep GitHub Actions workflows, branch protections, checks, and review flow.
If the run is slow because of deploy approvals, third-party API waits, fixed sleeps, or macOS and Windows jobs, solve those directly; a faster Linux runner is not the lever.
Key caveats
- The right fix depends on your own run timeline; a faster runner does not fix a deploy approval, an external API wait, or a fixed sleep.
- StarSling runners are Ubuntu/Linux only; macOS and Windows jobs stay on GitHub-hosted runners.
- StarSling keeps GitHub Actions syntax and branch protections. It is not a replacement CI platform.
- For new accounts, AI-powered optimization PRs are only available to customers on paid plans and are not enabled by default.
FAQ
Why is my GitHub Actions workflow queued for so long?
Long pre-start delay can mean the job is waiting for available runner capacity, serialized by a concurrency group, or blocked by a needs dependency. Measure from the workflow run's created_at to the job's started_at. To isolate dependency time, read the workflow at the run's head_sha and map YAML job IDs to runtime rows, including matrix expansions. Compare the job's started_at with the latest upstream completed_at only when that mapping is unambiguous; otherwise report total pre-start delay without claiming a precise dependency-adjusted queue time. Then check whether superseded PR runs still occupy capacity and whether concurrency is scoped too broadly.
Why is GitHub Actions so slow even after the job starts?
Once the job starts, slow execution usually comes from runner hardware, dependency installs, full checkout history, Docker builds, one long test job, monorepo work that runs too broadly, or fixed waits inside tests and deploy setup.
Do bigger or faster runners actually help slow GitHub Actions?
They help when the job is CPU-bound, memory-bound, or queue-bound on runner capacity. They do not help deploy approvals, external API waits, fixed sleeps, or workflow work that should have been cached, skipped, or parallelized.
How do I tell whether the runner or the workflow is the bottleneck?
Rerun the same job on stronger Ubuntu hardware without changing steps. If the expensive steps shrink, runner hardware mattered. If they do not, inspect workflow waste such as missing caches, full checkout history, unsharded tests, broad triggers, or fixed sleeps.
What should I fix first if GitHub Actions is taking too long?
Fix the largest measured wait first. Queue wait points to concurrency and capacity. CPU-heavy execution points to runner hardware. Repeated setup or irrelevant jobs point to caching, checkout, affected builds, sharding, and path filters.
Is StarSling a replacement for GitHub Actions?
No. StarSling keeps GitHub Actions workflows and changes supported Ubuntu/Linux runner labels. The workflow syntax, checks, branch protections, and PR review process stay in GitHub Actions.
Find the slow part, then run it faster
Keep GitHub Actions workflows. Move supported Ubuntu jobs to faster runners, then let optimization PRs improve the workflow over time.
Last reviewed October 6, 2026