"Start the build. Go make coffee. Come back. Still running."
That was the daily reality on the enterprise e-commerce platform I got pulled into. The Jenkins pipelines were so slow that developers measured build time in coffee runs, not minutes. Now multiply that by every pull request, every feature branch, every hotfix, across a whole engineering org — and you get a very expensive habit nobody had bothered to price. I was brought in for exactly one thing: make it fast again. This is the honest story of that Jenkins to GitHub Actions migration — what I found, what I actually changed, and what moved the needle.
The legacy pain was textbook
Everything about the setup was the kind of thing you nod at because you've seen it ten times before. Everything ran sequentially. There was no build caching, so every single run was a full rebuild from scratch. Shared runners queued for twenty minutes before a build even started. And there was a layer of flaky tests nobody dared touch — the accepted fix was to re-run and hope for green.
That last part matters more than it sounds. When your only recovery move is "run it again," you've already lost. The pipeline stops being infrastructure and becomes a slot machine.
I started with a map, not a migration
Before I wrote a single line of new YAML, I mapped every pipeline that was actually running. Not the documentation — there wasn't any. The real, live jobs. There were 47 of them. Some hadn't been touched in three years and were still firing every day. Nobody in the building could tell me what half of them deployed.
This is the step people skip, and it's the one that saves you. You cannot modernize what you can't see. So I inventoried the truth on the ground first, then found the bottlenecks:
- Sequential test execution — no reason for it, just how it grew over the years
- Full dependency install on every run — nothing was cached, so every build re-downloaded the world
- Zero parallelism across services — everything waited its turn
- Manual approval gates — bottlenecked on one human who was permanently in meetings
Here's the thing I kept repeating to stakeholders: the tool was not the problem. Swapping Jenkins for GitHub Actions and keeping the exact same shape would have bought me almost nothing. The migration was the excuse. The architecture change was the point.
The new architecture
Instead of a monolith of snowflake jobs, I built something modular and boring — boring in the best possible way.
- Shared, reusable workflows — one source of truth every repo in the org could call, instead of 47 hand-maintained variations
- Matrix builds — tests running in parallel across multiple Node versions instead of one slow lane
- Cached dependencies — so a build stopped paying the full install tax every time
- Build analytics per pull request — so a developer could actually see whether their change made the build slower
- Health-check gated deployments with automatic rollback — no more crossing fingers on a deploy
Underneath it all sat a single 634-line universal pipeline template. Every service deploys the same way now. No more snowflake configs, no more "well, it works on my Jenkins." At enterprise scale, that standardization is worth as much as the raw speed.
The result
Builds that used to take 55 minutes now finish in 7.
That's the headline number, and it's real. But the number I actually care about is the behavior change behind it. Developers stopped making coffee during builds, because the build finishes before the kettle boils. One dev told me it felt like working at a different company. That's the win — not the seven minutes, but the fact that shipping stopped feeling like a punishment.
The hardest part wasn't technical
I'll be honest about this. The parallel builds, the caching, the matrix testing — that's just engineering. It's knowable, it's finite, you grind it out. The genuinely hard part was convincing teams that the pain of changing was smaller than the pain of staying. People had made peace with the coffee runs. They'd built their whole day around a broken pipeline. Change is a threat until the moment it isn't.
Your pipeline is a product
Here's what I want you to take from this. A slow pipeline is not a minor inconvenience you route around. It's a tax on every developer, every single day. It quietly kills momentum, and then it kills morale.
Your CI/CD pipeline is a product, and your developers are its users. Measure it. Optimize it. Treat a 55-minute build as the incident it actually is. Do that, and you give people back the thing that made them want to build software in the first place — the feeling of shipping.
So, honestly: how long is your slowest pipeline right now — and have you just quietly accepted it?