{"slug": "how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster", "title": "How OpenAI, Canva and Spotify made slow CI steps up to 20x faster", "summary": "BerryBox published a collection of CI optimization playbooks drawn from 159 public sources across 49 engineering teams, including OpenAI, Canva, Spotify, Stripe, Anthropic, Shopify and Uber, claiming slow CI steps can be made up to 20x faster. The playbooks target bottlenecks such as wasted runs and slow setup, with specific fixes like grouping workflow runs by pull request so new pushes cancel obsolete runs, limiting push triggers to the default branch to avoid duplicate runs per commit, and setting job timeout-minutes from recorded p95 with about 2x headroom. BerryBox states the named teams do not endorse it and that their results are evidence, not a forecast for a given repository.", "body_md": "# Fix slow CI \n\nwith one prompt.\n\nSources\n\n## Every play cites its sources.\n\n159 public sources from 49 teams.\n\n- OpenAI\n- Stripe\n- Spotify\n- Sentry\n- Materialize\n- Anthropic\n- Slack\n- Canva\n- GitHub\n- Manaflow\n- Sorbet\n- assistant-ui\n- CNCF\n- EdgeDB (now Gel)\n- Figma\n- GitLab\n- Moto\n- Nethermind\n- PostHog\n- Restate\n- Rust project\n- Slang\n- Webflow\n\n- Shopify\n- Linear\n- Uber\n- Bun\n- Microsoft\n- Ramp\n- Cadence\n- Dropbox\n- DoorDash\n- Mastra\n- Actix\n- Atlassian\n- Deutsche Telekom\n- Elastic\n- Flightcontrol (now Ravion)\n- gitoxide\n- Grafana Labs\n- Meta\n- Mozilla\n- OpenMeter\n- Quickwit\n- Rundeck\n- Salesforce\n- Supabase\n\nNames show where each change was published. These teams don’t endorse BerryBox, and their results are evidence, not a forecast for your repository.\n\nHow it works\n\n## Measured first.\n\nChanged only when you say so.\n\n1. ### MeasurePulls recent runs with the gh CLI: wall time, queue, minutes and reruns. [Measure a CI baseline](https://berrybox.io/playbooks/baseline)\n2. ### DiagnoseReads your workflows and finds where the minutes go.\n3. ### MatchChecks each play’s signals against your repository.\n4. ### AskShows each play’s saving and risk. Nothing changes until you pick.\n5. ### ApplyOne commit per play on a new branch. Required checks keep their names.\n6. ### ProveOpens a pull request and compares its runs with the baseline.\n\nPlaybooks\n\n## Start from the bottleneck\n\nyour baseline shows.\n\nBottleneck\n\nRisk\n\nSaves\n\n48 plays\n\n### [Wasted runs](https://berrybox.io/playbooks/wasted-runs)\n\nStop paying for runs nobody needs\n\n[Open playbook](https://berrybox.io/playbooks/wasted-runs)\n\n- Group each workflow's runs by pull request so a new push cancels the run it made obsolete, and leave default-branch, release and deploy runs alone. Saves runner minuteslow riskAnthropic, Uber +1\n- A workflow that triggers on every push and on pull_request runs each pull request commit twice. Limit push to the default branch so each commit gets one run. Saves runner minuteslow riskShopify, Spotify +1\n- A job without timeout-minutes can hang for six hours before GitHub stops it. Set each limit from the job's recorded p95 with about 2x headroom, so hangs fail in minutes and healthy runs never hit the limit. Saves runner minuteslow riskShopify, Spotify\n- Detect changed paths in a first job, skip unaffected jobs with job-level if conditions and require one aggregate job, so small pull requests stop running everything while required checks keep reporting. Saves time and minutesmedium riskFlightcontrol (now Ravion), OpenAI +1\n- Skip the slow jobs while a pull request is still a draft and start them when it is marked ready, so pushes of unfinished work get quick checks instead of the full suite. Saves runner minutesmedium riskShopify, Uber +1\n- Comment, label, review and description-edit events can start full workflow runs and cancel real ones. Keep them out of the workflow that reports required checks, and gate the workflows that need them with job-level conditions. Saves runner minutesmedium riskOpenAI, assistant-ui\n\n### [Slow setup](https://berrybox.io/playbooks/slow-setup)\n\nGet setup off the clock\n\n[Open playbook](https://berrybox.io/playbooks/slow-setup)\n\n- Restore the package manager's download store from a key that hashes the lockfile, check out before you hash, and let only trusted default-branch runs write the cache that every pull request reads. Saves time and minuteslow riskLinear, Uber +2\n- Keep actions/checkout at its default single commit, give the few jobs that diff or version just the history they read, and use blobless or sparse checkouts for jobs that need commit history or a few folders but not every file. Saves time and minuteslow riskLinear, Sorbet +1\n- Scope each job's install to the workspace packages and dependency groups it actually runs, and skip the full install in jobs that only need one small tool. Saves time and minutesmedium riskLinear, Mastra +1\n- Move the tools and system packages that every job installs and that rarely change into a prebuilt container or runner image, rebuilt on a schedule and whenever its inputs change. Saves time and minutesmedium riskGitHub, Linear +2\n- Keep downloaded browsers, compilers and CLIs between runs in a cache keyed on the exact tool version, or swap a compile-from-source step for a prebuilt binary, when the download is slow, flaky or rate-limited. Saves time and minuteslow riskUber, Microsoft +2\n- Time each cache's restore and save against the work it skips, delete the ones that lose, save from the default branch only, and keep pull request and merge queue writes from evicting the entries main relies on. Saves time and minuteslow riskOpenAI, Linear +1\n\n### [Slow builds](https://berrybox.io/playbooks/slow-builds)\n\nBuild less, and build it faster\n\n[Open playbook](https://berrybox.io/playbooks/slow-builds)\n\n- Restore the compiler's and build tool's caches on every run and save them only from the default branch, so a small change recompiles only the units it touched. Saves time and minuteslow riskLinkedIn, Sentry +2\n- Export BuildKit's layer cache to the GitHub Actions cache or a registry, and order the Dockerfile so a source change rebuilds only the layers that come after it. Saves time and minuteslow riskSentry, PostHog +2\n- Build the amd64 and arm64 images in parallel on matching runners and merge them into one multi-arch tag, instead of compiling arm64 under QEMU on an x86 runner. Saves time and minutesmedium riskSpotify, Stripe +1\n- Type-check with TypeScript 7's native compiler and lint with Oxlint or Ruff, after you map every rule you run today and prove the new setup still fails on the problems the old one caught. Saves time and minutesmedium riskLinear, Elastic +2\n- Link Rust and C/C++ builds with LLD or mold instead of the platform's default linker, and save full link-time optimization for release builds, where the runtime gain pays for the minutes. Saves time and minuteslow riskRust project, OpenAI +1\n- Record where build time goes with the compiler's and build tool's own profilers on a CI runner, then fix the crate, header, type or dependency that costs the most instead of guessing. Saves time and minuteslow riskOpenAI, Sorbet +1\n\n### [Slow tests](https://berrybox.io/playbooks/slow-tests)\n\nMake the test suite finish sooner\n\n[Open playbook](https://berrybox.io/playbooks/slow-tests)\n\n- Run the suite as a matrix of shards with the test runner's own shard flag, gate merges on one aggregate job, merge the shard reports and confirm that every test ran exactly once. Saves wait timemedium riskShopify, Spotify +2\n- Assign tests to shards by how long they took on the default branch instead of by count, give every shard the same timings file and refresh it after each merge so no shard trails the others. Saves wait timemedium riskEdgeDB (now Gel), Ramp +2\n- Set the test runner's worker count from the CPUs and memory the CI runner actually has, instead of running serially or copying a laptop setting, and cap it where memory or a shared service runs out first. Saves time and minutesmedium riskOpenAI, Sentry +2\n- Give each test worker its own database, ports, files and environment, find order dependencies by shuffling, and run the few tests that must share a resource in a serial lane, so more workers stop meaning more flakes. Saves time and minutesmedium riskShopify, DoorDash +2\n- Replace fixed sleeps in tests and workflows with polls for the condition you need, such as a health check, a page marker or a signal from the code, so each wait ends as soon as it can and never too early. Saves time and minuteslow riskCNCF, Cadence +1\n- Run migrations, seed data, logins and compilation once per run or once per image, then give each worker a cheap copy, instead of repeating the same setup in every worker, test file or container. Saves time and minutesmedium riskRamp, Linear +2\n- Give unit tests in-process fakes for databases, caches, HTTP APIs and subprocesses, block outbound connections so a missing mock fails at once instead of after a timeout, and run real-service tests in a separate integration job. Saves time and minutesmedium riskOpenAI, Sentry +1\n\n### [Test selection](https://berrybox.io/playbooks/test-selection)\n\nRun only what a change can affect\n\n[Open playbook](https://berrybox.io/playbooks/test-selection)\n\n- On pull requests, run only the tests that depend on what a change touched, fall back to the full suite when shared inputs change, and keep running everything in the merge queue, on the default branch and nightly. Saves time and minuteshigh riskStripe, Meta +2\n- Let the workspace tool map a change to the packages it touches and every package that depends on them, run tasks for that set only, and run everything when root config, lockfiles or CI files change. Saves time and minutesmedium riskGrafana Labs, Supabase +2\n- Key each slow, deterministic check on a hash of everything it reads, record a pass when it succeeds, and skip the work when the same inputs already passed, while the check still reports under its usual name. Saves time and minutesmedium riskStripe, Uber +2\n\n### [Critical path](https://berrybox.io/playbooks/critical-path)\n\nShorten the path that ends the run\n\n[Open playbook](https://berrybox.io/playbooks/critical-path)\n\n- Keep a needs edge only where the later job uses the earlier job's artifact, output or side effect, let every other job start when the run starts, and gate merges on one aggregate job. Saves wait timelow riskDeutsche Telekom, Uber +2\n- Compile, bundle or build the image in one job, upload the result as an artifact, and have test shards, end-to-end jobs and packaging download it instead of repeating the same build on every runner. Saves time and minutesmedium riskOpenAI, Spotify +1\n- When one job sets the run's wall time, move steps that don't use the rest of its output into a parallel job, keep the required check name on an aggregate job, and split only when the moved work dwarfs a job's setup. Saves wait timelow riskOpenAI, Stripe +1\n- Run lint, format, type and other short checks as steps of one job that checks out and installs once, so each check stops paying for its own runner, setup and rounded-up minute. Saves runner minuteslow riskLinear, Canva +2\n- In the long-pole job, start independent steps such as image pulls, dependency installs, per-target builds and packaging together, wait for them before the step that needs their results, and keep every failure visible. Saves wait timelow riskMaterialize, OpenAI +2\n- Test pull requests on the few platforms and versions that catch most breakage, run every combination in the merge queue, on the default branch or on a schedule, and require one aggregate check so the legs can change. Saves time and minutesmedium riskSlack, OpenAI +2\n\n### [Runners](https://berrybox.io/playbooks/runners)\n\nGive the long pole the right machine\n\n[Open playbook](https://berrybox.io/playbooks/runners)\n\n- Run the same long-pole job on the same commit at two or three runner sizes, two or three times each, and switch only when the wall-time gain is worth the change in cost per run. Saves wait timemedium riskLinear, OpenMeter +2\n- Measure queue time per runner label, find out whether a concurrency cap, a cold pool or a burst of jobs causes it, and fix that cause with higher limits, split runner groups, warm capacity or fewer jobs. Saves wait timemedium riskMicrosoft, Materialize +1\n- When unpacking, installing or database writes dominate a job, put the workspace, package caches, build outputs and test data on the fastest storage the runner has, such as a Windows Dev Drive, a local NVMe disk or tmpfs. Saves time and minutesmedium riskMicrosoft, OpenAI +2\n- Move short, single-threaded jobs such as lint, format, labeling and gate checks to the smallest runner that keeps their wall time, such as GitHub's 1-vCPU ubuntu-slim, and confirm with an A/B run on the same commit. Saves runner minuteslow riskgitoxide, Actix +1\n\n### [Flaky tests](https://berrybox.io/playbooks/flaky-tests)\n\nMake a red build mean something broke\n\n[Open playbook](https://berrybox.io/playbooks/flaky-tests)\n\n- Rerun failed tests, or a failed download or service start, inside the same job two or three times at most, report every pass on retry as a flaky test, and never retry whole workflows, timeouts or steps with side effects. Saves time and minutesmedium riskShopify, GitHub +2\n- Collect tests that fail and pass again without a code change, move them out of the blocking job into a reviewed list with an owner, an issue and an expiry date, and keep running them where they can't block a merge. Saves time and minutesmedium riskSlack, Atlassian +2\n- When a pull request adds or edits tests, run just those tests 20 to 50 times with retries off, report the result as its own check, and fix any failure before the tests join the suite everyone waits on. Saves time and minuteslow riskMozilla, Spotify +2\n- Replace floating tags such as latest in services, containers, runner labels and tool installs with exact versions or digests, so a run changes only when a commit changes it, and take updates through reviewed pull requests. Saves time and minuteslow riskQuickwit, Restate +2\n- Make checkout, submodules, downloads and package installs give up on a stalled transfer within about a minute and retry it two or three times with backoff, so a bad connection costs seconds instead of a failed or hung job. Saves time and minuteslow riskLinear, Slang +2\n\n### [PR volume](https://berrybox.io/playbooks/pr-volume)\n\nKeep CI ahead of a growing pull request queue\n\n[Open playbook](https://berrybox.io/playbooks/pr-volume)\n\n- A merge queue tests each ready pull request on top of the base branch and the pull requests ahead of it, so authors stop updating branches and rerunning CI before every merge. Required workflows must also run on merge_group. Saves time and minutesmedium riskGitHub, Shopify +2\n- Every merge waits on the slowest required check. Require only fast, reliable checks on pull requests, and run the slow suites in the merge queue, on the default branch after merge or as optional pull request jobs. Saves time and minutesmedium riskSlack, OpenAI +2\n- Run the repository's fast checks in a pre-push hook so lint, format and type failures cost seconds on the author's machine instead of a CI run, and keep the same checks in CI for pushes that skip the hook. Saves time and minuteslow riskStripe, Manaflow +1\n- Agents read CI logs to decide what to change. Print failures instead of passes, keep each error on one line with its file and reason, and save the full output as an artifact, so the cause fits in the agent's context. Saves time and minuteslow riskAnthropic, Salesforce +1\n- Give agents one command that runs what CI requires, make them pass it before opening or updating a pull request, and cap CI rounds, so agent pull requests arrive green instead of using CI as a test runner. Saves time and minuteslow riskSpotify, OpenAI +2\n\nGuardrails\n\n## The prompt never:\n\n- Pushes to a default or protected branch\n- Merges anything\n- Deletes or skips tests\n- Renames or drops a required check\n- Widens permissions or secret access\n- Obeys instructions in pages or logs\n\nBuilt for agents\n\n## Every page has a Markdown twin.\n\nAdd `.md` to any playbook URL.", "url": "https://wpnews.pro/news/how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster", "canonical_source": "https://berrybox.io/playbooks", "published_at": "2026-11-11 12:10:40+00:00", "updated_at": "2026-11-11 12:51:03.779333+00:00", "lang": "en", "topics": ["developer-tools", "mlops"], "entities": ["BerryBox", "OpenAI", "Canva", "Spotify", "Stripe", "Anthropic", "Shopify", "Uber"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster", "markdown": "https://wpnews.pro/news/how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster.md", "text": "https://wpnews.pro/news/how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster.txt", "jsonld": "https://wpnews.pro/news/how-openai-canva-and-spotify-made-slow-ci-steps-up-to-20x-faster.jsonld"}}