How I Reduced CI Time by 60%: A Deep Dive into Pipeline Optimization
A comprehensive guide on optimizing CI/CD pipelines for test automation. Learn the strategies that cut execution time from 45 to 18 minutes at EPAM Systems.
The Challenge
When I joined EPAM Systems in 2022, the test automation suite for a major e-commerce platform was becoming a bottleneck. The CI/CD pipeline took 45 minutes to complete, causing:
- Slow feedback loops for developers
- Delayed deployments to production
- Reduced confidence in test results due to timeout failures
- Team frustration and decreased productivity
The goal: Reduce execution time by at least 50% without sacrificing test coverage or reliability.
The Investigation: Finding the Bottlenecks
Before optimizing anything, I needed to understand where time was being spent. Here's what I discovered:
Initial Metrics (45-minute pipeline)
| Stage | Time | % of Total |
|---|---|---|
| Setup & Dependencies | 8 min | 18% |
| Unit Tests | 5 min | 11% |
| E2E Tests (Sequential) | 28 min | 62% |
| API Tests | 3 min | 7% |
| Report Generation | 1 min | 2% |
The E2E tests were the clear bottleneck at 62% of total time.
Root Causes Identified
- Sequential Execution: Tests ran one-by-one in a single container
- No Caching: Dependencies downloaded on every run (~200MB)
- Unnecessary Tests: Some tests ran on every commit (even for documentation changes)
- Slow Selectors: XPath queries taking 2-5 seconds per element
- Network Delays: API calls without proper timeouts
- Docker Image Bloat: 1.2GB base image with unused dependencies
The Solution: 8-Step Optimization Strategy
1. Parallel Test Execution (Saved 18 minutes)
Before: 500 E2E tests running sequentially in one job
After: Tests split across 10 parallel jobs using GitLab CI matrix strategy
Impact:
- E2E time: 28 min → 10 min (64% reduction)
- Total time: 45 min → 27 min
2. Aggressive Dependency Caching (Saved 6 minutes)
Before: npm install downloading 200MB on every run
After: Layer-based caching with hash-based invalidation
Optimization: Used npm ci instead of npm install for faster, reproducible installs.
Impact:
- Setup time: 8 min → 2 min (75% reduction)
- Total time: 27 min → 21 min
3. Smart Test Selection (Saved 4 minutes)
Before: All 500 E2E tests ran on every commit
After: Changed test detection based on file changes
Impact:
- Docs-only commits: 21 min → 2 min (90% reduction)
- Average time across all commits: 18 min (60% reduction from original 45 min)
4. Optimized Docker Images (Saved 2 minutes)
Before: 1.2GB image with full Ubuntu + unnecessary tools
After: Multi-stage Alpine-based image
Impact:
- Image size: 1.2GB → 220MB (82% reduction)
- Pull time: 3 min → 1 min
5. Playwright Selector Optimization (Saved 3 minutes)
Problem: Slow XPath selectors causing timeouts
Before:
After:
Implementation: Added data-testid attributes to all interactive elements
Impact:
- Average selector time: 2.5s → 0.08s (97% reduction)
- Test stability: Fewer timeout failures
- Accumulated savings across 500 tests: ~3 minutes
6. API Mocking for E2E Tests (Saved 2 minutes)
Problem: Tests waiting for real API responses (300-500ms each)
Before: 500 tests × 10 API calls × 400ms = 33 minutes of waiting
After: Mock API responses for non-critical paths
Impact:
- API wait time: 400ms → 50ms per call (88% reduction)
- Total savings: ~2 minutes
7. Parallel Stages (Saved 1 minute)
Before: Stages ran sequentially (unit → e2e → api)
After: Independent stages run in parallel
Impact:
- Test stage time: Sequential → Parallel (longest job = 10 min)
8. Flaky Test Retry Logic (Improved Reliability)
Problem: Occasional network timeouts causing pipeline failures
Solution: Automatic retry with exponential backoff
Impact:
- False failure rate: 15% → 2%
- Developer confidence: Significantly improved
Final Results
Before vs After Comparison
| Metric | Before | After | Improvement |
|---|---|---|---|
| Total Pipeline Time | 45 min | 18 min | 60% faster |
| E2E Test Time | 28 min | 10 min | 64% faster |
| Setup Time | 8 min | 2 min | 75% faster |
| False Failure Rate | 15% | 2% | 87% reduction |
| Daily Pipeline Runs | 50 | 50 | - |
| Time Saved Per Day | - | 22.5 hours | - |
| Time Saved Per Year | - | ~5,600 hours | - |
Cost Savings
Assuming CI runner costs $0.50/minute:
- Before: 45 min × 50 runs/day × $0.50 = $1,125/day
- After: 18 min × 50 runs/day × $0.50 = $450/day
- Savings: $675/day or $246,375/year 💰
Key Takeaways
1. Measure First, Optimize Second
Don't guess where the bottleneck is—profile your pipeline to find the real culprits.
2. Parallelization is Your Best Friend
Splitting tests across multiple jobs is the single biggest win (saved 18 min in my case).
3. Cache Everything
Dependencies, Docker layers, build artifacts—aggressive caching saves minutes per run.
4. Smart Test Selection
Don't run 500 E2E tests when someone updates the README.
5. Optimize Selectors
Fast, reliable selectors (data-testid, role-based) are crucial for E2E test performance.
6. Mock When Possible
Real API calls are slow and unreliable—mock non-critical paths.
7. Retry Flaky Tests
Automatic retries with exponential backoff reduce false failures significantly.
8. Monitor Continuously
Track pipeline metrics over time to catch performance regressions early.
Tools & Technologies Used
- CI/CD: GitLab CI/CD
- Test Framework: Playwright (E2E), Jest (Unit)
- Mocking: MSW (Mock Service Worker)
- Containerization: Docker (Alpine-based images)
- Monitoring: GitLab CI Analytics, Grafana
What's Next?
Future optimizations I'm exploring:
- Predictive Test Selection: ML-based test prioritization based on code changes
- On-Demand Test Environments: Ephemeral preview environments for faster testing
- Visual Regression Testing: Parallel visual diff checks with Percy/Chromatic
- Test Impact Analysis: Skip tests unaffected by code changes
Conclusion
Optimizing CI/CD pipelines is not a one-time effort—it's an ongoing process. By applying these 8 strategies, I reduced our pipeline time from 45 minutes to 18 minutes (60% faster), saving the team 22.5 hours per day and $246K per year in CI costs.
The bottom line: Fast feedback loops lead to happier developers, faster deployments, and higher-quality software.
If you're facing similar challenges or want to discuss pipeline optimization strategies, feel free to reach out!
Published on December 15, 2025 · 12 min read