Creuto is now an OpenAI Select Partner Read More

Software Architecture & Technical

Speed up CI pipeline runs: Linear's playbook for AI-era load

How to speed up CI pipeline runs when AI coding floods it: Linear's four fixes, the shard-setup maths, and when a GitHub Actions cache makes CI slower.

Speed up CI pipeline runs: Linear's playbook for AI-era load

Linear's test suites almost quadrupled since the start of 2026 as agents wrote more of its code, yet pull request wait time fell from more than 6 minutes to just over 5 and runner time per test roughly halved. If you are trying to speed up CI pipeline runs that agents now fill faster than your runners can drain them, their write-up is the most specific public playbook we have seen. This post walks through what they changed, which parts transfer to your pipeline, and where the usual advice (cache everything, add shards) quietly makes things worse.

Does AI coding make CI slower?

AI coding does not make any single CI run slower; it makes the queue longer and the suite bigger. Linear's framing is exact: "Every PR still has to pass through CI, so as development accelerates, CI becomes a bottleneck, driving up infrastructure costs and leaving developers and agents waiting longer for feedback." The work started as an issue from their CTO titled "CI costs are high", with a request to make CI faster at the same time.

Their numbers show why this does not fix itself. Linear is adding roughly 2,000 tests a week, and it estimates that without the work "today's test suite would take roughly 11 minutes, close to double what developers wait now." Agents also write the majority of their tests now, which matters later: any speed-up that depends on how tests are written has to be taught to the agents too.

We see the same shape in the pipelines we set up for clients. The first symptom is rarely a failed build. It is a pull request that sits green-but-waiting while three others queue behind it, and review that bunches up at the end of the day. We have written about that review side in how agent productivity moves the bottleneck to review; CI is the same bottleneck one step earlier.

Four ways to speed up CI pipeline runs, from Linear's rework

Linear grouped its changes into four areas: upgrade infrastructure and tooling, optimise the jobs that gate other work, reduce repeated setup, and make test execution more efficient. Their codebase is mostly TypeScript, but they note that "many of these optimizations apply across languages and toolchains." The order matters, because the later steps only pay off once the earlier ones are done.

1. Upgrade the machines and the toolchain first

The earliest gains needed almost no pipeline changes. Moving workloads off GitHub Actions' own runners to third-party runners with faster CPUs, faster storage and better cache infrastructure made jobs run 34% faster on average in a like-for-like comparison of the two days either side of the switch, with tsc dropping 52%. Switching to tsgo, the native TypeScript compiler, then cut the weekly median of the tsc check by 73%, "large enough to move the bottleneck off of typechecking entirely."

Lint got the same treatment. Some custom ESLint rules needed type information, so every lint run built the full type graph. Rewriting those rules to use syntax-tree analysis let ESLint drop TypeScript, cutting API lint time by 68% and full-repository lint by 55%, and made a later move to Oxlint straightforward. If your lint job is one of your slowest, our note on type-aware linting with tsgolint and Oxlint covers the trade-off in more depth.

There is a cost Linear did not hide. Third-party runners sit outside GitHub's network, and their checkout times grew and sometimes hung on a degraded link. They replaced actions/checkout with a composite action that retries with backoff, sets GIT_HTTP_LOW_SPEED_LIMIT and GIT_HTTP_LOW_SPEED_TIME so a stalled fetch aborts after about 30 seconds, and uses a persistent git mirror. Faster machines brought a new failure mode, and it needed engineering to contain.

2. Shrink the jobs that everything else waits for

Small gating jobs sit on the critical path. At Linear, a change-detection job decides which checks run, and none of the eight API test shards can start until it finishes. Capping fetch depth took the slowest gate from 94 seconds to 20; removing checkout from jobs that never needed a working tree cut those from 27 seconds to 7; a sparse, blobless checkout for push and merge-queue events saved roughly another 11. The change-detection job's median fell from 26 to 8 seconds, and its slowest run from 138 to 37.

They also moved a cache-marker write out of the final pre-merge check into a job that runs after the shards but gates nothing. That shaved 42 seconds off the merge path for every API pull request and merge-queue entry. Together, the gating changes took roughly a minute off the required check for API pull requests on cache misses.

3. Stop paying for the same setup on every job

Setup is where agent-scale CI bleeds money, because it repeats per job, per shard and per push. Linear's API test shards each spent 7 to 8 seconds installing the same Postgres client, so they baked it into a small CI base image. Restricting the pnpm install to the API package in their monorepo cut install from 44–73 seconds to 16–18. Loading a generated schema snapshot instead of replaying every database migration cut database setup from roughly 12 seconds to 1–2 per container.

The biggest single saving in this group came from batching. Seven independent checks each booted a runner, checked out the repo and installed dependencies to do seconds of work. Consolidating them into two jobs that run the seven tasks concurrently saved roughly 87,000 runner-minutes a month, based on June usage, equal to 11.8% of Linear's total CI usage.

4. Make the tests themselves cheaper to run

Only after setup was cheap did more parallelism pay. Vitest distributes work by file, not by the duration of individual tests, a behaviour the Vitest performance guide states plainly: it "splits your test files, not your test cases, into shards." A few very large files were holding up whole shards, so Linear split them. Going from four shards to eight made the critical job roughly 19% faster and 19% cheaper in their first benchmark, and a week later the slowest shard had dropped from 5.25 minutes to 4.33.

The largest single improvement was riskier: an opt-in Vitest project with isolate: false, so eligible files share a module registry within a worker instead of rebuilding the entity, GraphQL and decorator graph each time. The slowest shard fell from roughly 300–379 seconds to about 195, and total API-shard runner time from about 32.8 to 22 minutes per run, worth roughly 17% in monthly savings at their volume. They made eligibility an explicit per-file opt-in, added teardown for shared state, left files with fake timers or tangled state isolated, and updated their agents' skills so generated tests follow the same rules.

Test sharding only pays when setup is cheap

The most transferable lesson in the post is arithmetic, not tooling. Every shard pays the full setup cost, so doubling shards doubles setup time. At 110–140 seconds of setup per shard, eight shards would have burned 15–19 minutes of runner time on setup alone, "more than the tests themselves." After the setup work brought per-shard setup to about 40 seconds, eight shards spent 7.5 minutes on setup, less than the 8.3 minutes four shards had spent before.

That is why adding shards is the wrong first move for most teams. It shortens the wall-clock wait and raises the bill. Linear's own chart shows machine time per test spiking when shards were added. Measure setup per shard first. If it is a large share of each shard's runtime, fix setup; if it is small, shard.

CI caching and sharding: when a cache makes CI slower

The default advice for reducing CI costs is to cache dependencies, and GitHub's dependency caching reference makes it easy: the setup-node action creates and restores caches for npm, Yarn and pnpm with minimal configuration, and actions/cache restores by exact key, then partial key, then your restore-keys in order. For most pipelines, that is still the right starting point.

Linear's counter-example is worth taking seriously. They tested caching node_modules and found it faster to rebuild: the key depended on a lockfile that changed often, and even a cache hit took about 28 seconds to restore against roughly 7.5 seconds for a filtered install. The cache "was adding save time and variability without giving us any discernible advantage." Together with the base image and filtered install, that decision helped cut per-shard setup by roughly 44%, from 110–140 seconds to 67–73.

GitHub's own limits explain why caches disappoint in busy repositories:

  • Cache entries not accessed in over 7 days are removed, and the default total is 10 GB per repository; beyond that, GitHub evicts the least recently used caches, which the docs warn can cause "cache thrashing".
  • A cache created by a pull request run is scoped to that pull request's merge ref and "can only be restored by re-runs of the pull request". Other pull requests cannot use it. If agents open many short-lived pull requests, warm the cache from runs on your default branch, which pull requests can restore from.
  • Uploads are limited to 200 per minute per repository and downloads to 1,500 per minute; beyond that, cache calls fail until the limit resets.

The docs also warn not to put tokens or credentials in cached paths, because anyone with read access can open a pull request and read a cache. That matters more when agents are editing workflows; we covered a related failure in GitHub Actions prompt injection and secrets.

How to speed up a CI pipeline in 2026: where to start

Linear measured two things throughout: how long a pull request waits on CI, and runner time per test. Those are the right pair, because optimising only the first raises cost, and only the second slows developers down. From their write-up and the pipelines we maintain, this is the order we would work in:

  1. Instrument wait time per pull request and runner minutes per test, and track the p90, not only the median.
  2. List the jobs on the critical path. Cut their checkout depth and anything they do not need.
  3. Time setup per job. Bake shared tools into a base image, filter monorepo installs, and snapshot anything replayed on every run.
  4. Batch small checks that each boot a runner for seconds of work.
  5. Test whether each cache actually beats a clean install, and warm caches from the default branch.
  6. Split oversized test files, then add shards, then consider shared-state test modes with an explicit opt-in.
  7. Only then evaluate faster runners, and budget for the network and checkout issues they can bring.

This order is the wrong one if your runners are badly undersized; then step 7 may be step 1, as it was for Linear's earliest gains. Either way, write the rules into the prompts and skills your agents use, or the next thousand generated tests will undo the work. If you want a second pair of hands on the pipeline, that is our CI/CD implementation practice, and the test-suite side sits with QA and automation. The first deliverable is always the same: two numbers, wait per pull request and runner time per test, measured before anything changes.

Frequently asked questions

CI slows under AI coding because every pull request still passes through the same pipeline while the queue and the suite grow. Linear's suites almost quadrupled in 2026. The usual culprits are gating jobs on the critical path, setup repeated on every job and shard, and test files too large to split evenly.

CI costs fall fastest when you cut repeated setup before adding parallelism. Linear baked tools into a base image, filtered monorepo installs and batched seven small checks into two jobs, saving roughly 87,000 runner-minutes a month. Track wait per pull request and runner time per test together so one does not rise as the other falls.

Test sharding speeds up a CI pipeline only when per-shard setup is cheap, because every shard repeats setup. Linear calculated that eight shards at 110 to 140 seconds of setup each would spend 15 to 19 minutes on setup alone. After cutting setup to about 40 seconds, eight shards used less setup time than four.

Caching node_modules in GitHub Actions is worth testing, not assuming. Linear found a cache hit took about 28 seconds to restore, against roughly 7.5 seconds for a filtered pnpm install, because its lockfile changed often. GitHub's setup-node action creates and restores dependency caches for npm, Yarn and pnpm with minimal configuration, a simpler starting point.

GitHub Actions scopes a cache created by a pull request run to that pull request's merge ref, so only re-runs of the same pull request can restore it. Pull requests can restore caches from their base branch and the default branch, so warming caches with runs on main helps many short-lived pull requests.

Written by

Akash Mohapatra

Akash Mohapatra

Co Founder & Director

22 Sep 2026

·

10 min read

Share

LET'S CONNECT

Connect with Creuto!

Ready to take the first step towards unlocking opportunities, realizing goals, and embracing innovation? We're here and eager to connect.

We don't just aim to fit in – we strive to stand out. Experience the perfect blend of innovation, excellence, and trust that makes us truly unforgettable. Discover the difference with Creuto.

© 2026 Creuto All Rights Reserved