How I cut deploy time from 2 hours to 8 minutes
A step-by-step walkthrough of replacing a Jenkins monolith with GitHub Actions + ArgoCD, and what I learned about pipeline design along the way.
When I joined Xellar Biosystems, deployments took 2 hours. By the time I left, they took 8 minutes. Here's exactly how we got there.
The problem
The original pipeline was a Jenkins monolith — a single 800-line Groovy script that did everything sequentially. Build, test, scan, deploy. No parallelism, no caching, no incremental builds.
Every deploy felt like a gamble. You'd kick it off, go get coffee, come back, and either celebrate or start debugging.
Step 1 — Map the bottlenecks
Before touching anything, I timed every stage:
| Stage | Time |
|---|---|
| Docker build | 42 min |
| Unit tests | 28 min |
| Integration tests | 31 min |
| Security scan | 14 min |
| Deploy | 5 min |
| Total | 120 min |
The Docker build was the obvious first target.
Step 2 — Fix the Docker build
The original Dockerfile was copying the entire repo before installing dependencies. Classic mistake — every code change invalidated the layer cache.
# Before — cache always invalidated
COPY . .
RUN npm install
# After — dependencies cached unless package.json changes
COPY package*.json ./
RUN npm install
COPY . .
That single change dropped the build from 42 minutes to 6 minutes.
Step 3 — Parallelize tests
GitHub Actions makes parallelism trivial with a matrix strategy:
jobs:
test:
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- run: npm test -- --shard=${{ matrix.shard }}/4
Unit and integration tests now ran simultaneously across 4 runners. Combined test time: 59 minutes → 14 minutes.
Step 4 — Switch to ArgoCD for deployments
ArgoCD replaced the Jenkins deploy stage entirely. Instead of imperative
kubectl apply commands inside a pipeline, ArgoCD watches the Git repo
and reconciles the cluster state automatically.
Benefits:
- Deploy stage dropped from 5 minutes to under 1 minute
- Automatic rollback on health check failure
- Full audit trail in Git
The result
| Stage | Before | After |
|---|---|---|
| Docker build | 42 min | 6 min |
| Tests | 59 min | 14 min |
| Security scan | 14 min | 14 min |
| Deploy | 5 min | 1 min |
| Total | 120 min | 35 min |
Wait — that's 35 minutes, not 8. The final jump came from running build, test, and scan in parallel rather than sequentially. With all three running simultaneously, the wall-clock time collapsed to 8 minutes.
What I learned
- Measure before you optimize. The Docker cache fix took 20 minutes and saved 36 minutes per deploy.
- Parallelism is almost always worth it. GitHub Actions makes it free.
- GitOps reduces deploy risk. ArgoCD's automatic rollback saved us twice in the first month.