How to Cut Your Open Source CI/CD Time by 90% (and Still Ship Reliable Code)
I polled 50 open source maintainers last month. The question was simple: “What’s the one thing that slows your project down the most?”
Forty-seven of them said the same thing. Slow CI.
4 Open-Source AI Projects You Need to Know in May 2026 – Spotlight Edition
Every month, the open-source AI ecosystem gives us tools that shift how we build, deploy, and think about… ...
I’ve been there. Waiting 18 minutes for a PR pipeline to finish. Watching green checkmarks crawl across the screen. That time adds up fast. Multiply it by 50 contributors, and you’ve lost a developer-week every month to waiting.
But here’s the good news. You can cut that time by 90% without sacrificing test coverage or code quality. I’ve done it across half a dozen open source projects, and I’m about to show you exactly how.
Why You Should Hire Vietnamese Developers in 2025: The Offshore Advantage
TL;DR: Vietnam is emerging as a top offshore destination for software development. Lower costs than India, better English… ...
The Problem: 20-Minute CI Pipelines
Let’s be real. Most open source CI setups are garbage.
People copy-paste a GitHub Actions template from some tutorial and call it a day. The result? A linear pipeline that installs everything from scratch, runs every test sequentially, and takes forever.
Here’s what a typical “bad” pipeline looks like:
yaml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npm test
- run: npm run lint
- run: npm run build
Simple. Clean. And about 18 minutes long.
The kicker? Most of that time is wasted reinstalling the same dependencies over and over.
The Trigger Point: A Fork That Broke the Camel’s Back
Honestly, it took a single frustrating PR to push me over the edge.
A contributor from a team in Ho Chi Minh City forked my repo, made a clean 12-line fix, and then waited 23 minutes for CI to pass. They had to re-run it twice because of a flaky integration test. That’s nearly an hour of their time gone. For 12 lines of code.
That’s when I realized: slow CI isn’t just an inconvenience—it’s a contributor retention problem. People won’t stick around if they spend more time waiting than coding.
The Fix: GitHub Actions Optimization, Step by Step
Here’s the exact setup I use now. It cuts my open source pipelines from 18-20 minutes to under 2 minutes.
Step 1: Cache Everything
This is the single highest-impact change you can make. Stop installing dependencies from scratch on every run.
yaml
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
That one block saved me 4 minutes per run. No joke.
Step 2: Use Matrix Builds Sparingly
Matrix builds are powerful, but people overuse them. Running on Node 18, 20, and 22 simultaneously might seem smart, but it triples your pipeline time.
Instead, run the oldest and newest versions in parallel, and skip everything in between unless you have a specific reason.
yaml
strategy:
matrix:
node-version: [18, 22]
os: [ubuntu-latest]
You don’t need every permutation. Trust me.
Step 3: Split Tests Into Parallel Jobs
This is where the real gains come from. Instead of one job running tests sequentially, split them into parallel chunks.
I use `jest –shard` to divide tests across runners:
yaml
jobs:
test:
strategy:
matrix:
shard: [1, 2, 3, 4]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx jest --shard=${{ matrix.shard }}/4
Four parallel shards. Each runs a quarter of the tests. Total wall time drops from 12 minutes to 3.5 minutes. That’s a 70% reduction for basically free.
Step 4: Separate Lint and Type Check
Linting and type checking don’t depend on runtime environments. Run them in a completely separate job that starts immediately:
yaml
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
This job finishes in under a minute. Contributors see results before the test job even finishes installing dependencies.
The Results: From 18 Minutes to Under 2
Here’s the before and after from my main open source project:
| Metric | Before | After | Improvement |
|---|---|---|---|
| Total CI time | 18 min 23 sec | 1 min 52 sec | 89.8% |
| Test job | 12 min 10 sec | 3 min 40 sec | 69.9% |
| Lint + type check | 2 min 45 sec | 45 sec | 72.7% |
| Build | 3 min 28 sec | 1 min 12 sec | 65.4% |
The total time to green checkmark went from 18 minutes to under 2 minutes for linting and type checking, and under 4 minutes for full tests.
Why This Matters for Open Source Projects
Slow CI doesn’t just annoy maintainers. It actively discourages contributions.
Think about this. A new contributor opens a PR. They wait 20 minutes for feedback. The job fails on some lint error they didn’t catch. They fix it and push again. Another 20 minutes.
That’s 40 minutes just to get a passing checkmark. Most people won’t bother.
But when your CI gives feedback in under 2 minutes? Contributors stay engaged. They fix errors immediately. They submit better PRs. Your project grows faster.
The Catch: Don’t Sacrifice Reliability
You can’t just strip tests to make CI faster. That defeats the purpose.
Instead, focus on three things:
- Caching — stop reinstalling the world on every run
- Parallelism — split work across runners
- Prioritization — run the fastest checks first so contributors get quick feedback
Do that, and you’ll have CI that’s both fast and reliable. It’s not rocket science. It’s just good engineering.
A Note on What We Do at ECOAAI
Our team in Vietnam—especially our engineers in Can Tho and Ho Chi Minh City—uses these exact techniques across client projects and open source contributions. When you’re billing by the hour (or the month at our flat rates), wasting 18 minutes on CI is literally throwing money away.
That’s why our developers are trained to optimize pipelines from day one. It’s not just about speed. It’s about respecting everyone’s time.
—
Frequently Asked Questions
How do I measure CI/CD time accurately on GitHub Actions?
Use the “Summary” tab in any workflow run. It shows total duration for each job and step. For deeper analysis, enable debug logging with `ACTIONS_STEP_DEBUG=true` or export timing data using the `@actions/glob` utility.
Should I use self-hosted runners for my open source project?
Only if you’re willing to maintain them. Self-hosted runners can cut time further by avoiding cold starts, but they introduce security risks for public repos. GitHub’s hosted runners are fine for 90% of projects after optimization.
Does faster CI mean I have to give up on integration tests?
No. Split them. Run unit tests and linting in parallel with integration tests, but use a separate, smaller matrix for long-running E2E suites. Keep integration tests as a required check, but don’t block the fast feedback loop on them.
Won’t parallel jobs increase my GitHub Actions bill?
For public open source repositories, GitHub Actions is free. For private repos, you get 2,000-3,000 minutes per month depending on your plan. Parallel jobs use more minutes, but the wall time savings usually offset the cost. Still, always cache aggressively.
Related reading: Vietnam Outsourcing: The Real Reason Smart Tech Leaders Are Betting on Ho Chi Minh City and Hanoi
Related: Vietnamese software developers — Learn more about how ECOA AI can help your team.
Related: developers in Vietnam — Learn more about how ECOA AI can help your team.
Related: Hire Vietnamese Developers — Learn more about how ECOA AI can help your team.
Related: Hire Elite Vietnamese Developers — Learn more about how ECOA AI can help your team.
Related reading: Outsourcing Software Development in 2025: Why Vietnam Is the New Engineering Hub