CI < 10 minutes
CI under 10 minutes is the first meaningful milestone on the path to AI-native delivery infrastructure.
- Build caching is implemented (dependency cache, build artifact cache)
- Dedicated CI runners are allocated per team (no shared queue across all teams)
- CI completes in under 10 minutes (median)
- CI duration is tracked as a metric and reviewed monthly
- Cache hit rate exceeds 70%
- CI run duration dashboard showing median under 10 minutes
- Cache configuration in CI pipeline (e.g., actions/cache, Gradle build cache)
- Runner allocation configuration showing per-team resources
What It Is
CI under 10 minutes is the first meaningful milestone on the path to AI-native delivery infrastructure. At the Delegated (L2) maturity level, teams have recognized that their slow CI is a problem and have taken concrete, deliberate steps to address it - primarily through dependency caching, basic parallelization, and splitting the pipeline into fast and slow paths. The result is a pipeline that consistently completes in under 10 minutes for the majority of branch builds.
The 10-minute target is not arbitrary. It represents the threshold below which CI stops being a "go do something else" wait and starts being a "stay engaged" wait. A developer or agent that submits a change and gets feedback in 8 minutes can maintain context. They can review the results, make a correction, and re-submit before losing the thread of what they were working on. Above 10 minutes, the context switch is nearly inevitable. Below 10 minutes, continuous engagement with the feedback loop becomes viable.
For AI agents, 10 minutes is still far from ideal - agents can iterate much faster than 10-minute cycles allow - but it's the level at which agent-assisted workflows become meaningfully more productive than pure human workflows. At L2, teams are also starting to understand the relationship between CI speed and agent adoption: faster CI correlates directly with more agent use and higher agent task completion rates, because developers are willing to let agents iterate more freely when each iteration doesn't cost 18 minutes.
Reaching 10-minute CI typically requires three changes working together: caching (eliminating redundant dependency downloads), parallelization (running independent test groups simultaneously), and pruning (removing or mocking tests that were never fast to begin with). None of these requires exotic tooling - they're available in GitHub Actions, CircleCI, BuildKite, and GitLab CI with native features.
Why It Matters
- Agent iteration becomes viable - at 10 minutes, an agent can complete 6 iterations per hour, enough to tackle substantive tasks within a single working session
- Developer engagement with CI improves - developers who get results in under 10 minutes stay engaged with the feedback loop instead of context-switching away, catching issues faster
- Merge queue throughput increases - a 10-minute CI pipeline can process 6 PRs per hour per runner, compared to 3 PRs per hour at 20 minutes; throughput doubles for the same hardware cost
- Foundation for further optimization - once you have dependency caching and parallelization in place, the path to 5-minute and 2-minute CI is incremental, not a restart
- Demonstrates that CI speed is addressable - hitting the 10-minute target changes the team's mental model from "CI is slow because it has to be" to "CI speed is an engineering choice"
Getting Started
- Enable dependency caching in your CI platform - GitHub Actions, CircleCI, BuildKite, and GitLab CI all have native cache primitives. Cache your package manager's dependency directory (node_modules, ~/.gradle, ~/.m2, vendor/) keyed on your lock file hash. This alone typically saves 3-8 minutes on pipelines that were pulling dependencies fresh on every run.
- Identify and parallelize independent test groups - Most test suites have unit tests, integration tests, and E2E tests that can run in parallel CI jobs rather than sequentially. In GitHub Actions, use a matrix strategy to split test groups across parallel jobs. In CircleCI, use the
parallelismkey. Start with the coarsest split: unit tests as one job, integration tests as another. - Create a fast feedback job - Define a job that runs lint, type checking, and unit tests only - targeting under 3 minutes. This is the job that runs on every commit and gives agents their first signal. Slower integration and E2E tests can run in parallel or post-merge.
- Audit and mock slow external calls - Search your test suite for any test making real HTTP calls to external APIs, opening real database connections, or using real file system operations unnecessarily. Replace with mocks or test doubles. Real external calls are the most common cause of test suite slowness and flakiness simultaneously.
- Cache Docker layer builds - If your CI builds Docker images, enable layer caching. In GitHub Actions, use
docker/build-push-actionwithcache-fromandcache-to. In CircleCI, use the Docker layer caching feature. Image builds that take 5-8 minutes cold can take under 1 minute with warm cache. - Measure and report progress - After each optimization, record the new p50 CI time and share it with the team. Use GitHub Actions' built-in timing, CircleCI's Analytics tab, or BuildKite's pipeline analytics. Progress visibility keeps the effort moving and demonstrates ROI.
Parallelizing your test suite across 4 jobs doesn't always give you 4x speedup - there's overhead in job startup, cache restoration, and reporting. A realistic expectation for basic parallelization is 2-3x speedup on the test execution phase. That's still significant, and it compounds with caching gains.
Common Pitfalls
Caching without cache invalidation strategy. Caching package manager dependencies keyed on a lock file is correct - when the lock file changes, the cache is invalidated and rebuilt. But teams sometimes cache build outputs without proper invalidation, leading to stale cache hits that silently serve old build artifacts. Always cache on a key that reflects the actual inputs to the cached stage.
Parallelizing without test isolation. When you split a test suite across parallel jobs, tests that share global state (a single test database, a shared file, a global configuration object) will conflict. Before parallelizing, audit for shared state. Tests that share state must either be isolated (each job gets its own database instance) or must run sequentially.
Stopping at 10 minutes as if it's the destination. Ten minutes is a milestone, not a target. It proves the approach works and gets agents to a viable iteration rate. But teams that stop at 10 minutes miss the compounding value of getting to 5 minutes and then 2 minutes. Set the next target before you finish celebrating the current one.
Optimizing CI but not local development. Developers who run tests locally before pushing should get the same fast feedback that CI provides. If CI is 8 minutes but local test runs are 25 minutes, developers stop running tests locally and push speculatively to CI. Keep the local test path fast alongside the CI path.
Adding parallelization without runner capacity to support it. If you split into 8 parallel jobs but only have 4 available runners, 4 jobs will queue while the first 4 run. Net result: similar total time, more complexity. Match your parallelism level to your actual runner capacity, or provision more runners alongside the parallelization change.
How Different Roles See It
Bob's team has committed to getting CI under 10 minutes. He's assigned one developer to own the CI sprint and has set a public 30-day target. Midway through, the pipeline is at 12 minutes - improved from 18, but not yet at target. The remaining time is dominated by a 7-minute integration test suite that the team has never touched.
Bob should not extend the deadline; he should triage. The 7-minute integration test suite needs to be split into parallel jobs. Bob should authorize the developer to spend two days isolating tests into parallelizable groups (unit, integration, E2E) and setting up a matrix strategy in the CI YAML. He should also check: does the team have enough runners to support this parallelism? If the shared runner pool is the bottleneck, Bob should approve a temporary dedicated runner allocation to unblock the CI work. The 10-minute target is achievable; the blocker is usually authorization to make the needed infrastructure changes, not technical complexity.
Sarah has established a CI feedback latency dashboard and is tracking the team's progress toward 10-minute CI. The data shows that the p50 CI time has dropped from 18 minutes to 12 minutes after the caching changes, but the p95 is still 22 minutes. The variance is coming from a specific integration test file that occasionally makes a real network call to a third-party service.
Sarah should flag the high-variance test as a priority fix - not just because it's slowing down CI, but because the network dependency makes CI results unreliable (the test fails when the external service has a hiccup, not when the code is broken). She should document the impact: a 22-minute p95 means that 1 in 20 CI runs is causing a 22-minute wait, and agents that hit this outlier are stalled for much longer than expected. Quantifying the tail latency problem - not just the average - is how Sarah makes the case for prioritizing test isolation as engineering work rather than cleanup.
Victor has already gotten his personal projects to 6-minute CI through local experimentation. He's using GitHub Actions with a matrix strategy across 6 parallel test jobs, dependency caching, and Docker layer caching. The results are clear: his agent iteration rate is 3x what it was at 18-minute CI. He wants to replicate this across the team.
Victor should write a CI optimization playbook: a concrete, step-by-step document that shows exactly what changes he made, in what order, with before/after timing data. The playbook removes the "how do we do this?" friction for other team owners. Victor should also propose a CI optimization "office hours" session where he walks through the changes live on another team's pipeline - the best way to transfer tacit knowledge about CI optimization is hands-on, not documentation alone. The session also surfaces team-specific constraints (unusual test frameworks, special runner requirements) that the playbook doesn't cover.
Further Reading
Where does your team actually sit on this?
This guide describes one level of one area. Run the assessment to place your team across all 16 areas, see which gates you have passed, and get a report you can take to your stakeholders.