Skip to main content
Back to blog

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.

8 min read
by Andrii Peretiatko
CI/CDPerformanceDevOpsTestingGitLab CI

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)

StageTime% of Total
Setup & Dependencies8 min18%
Unit Tests5 min11%
E2E Tests (Sequential)28 min62%
API Tests3 min7%
Report Generation1 min2%

The E2E tests were the clear bottleneck at 62% of total time.

Root Causes Identified

  1. Sequential Execution: Tests ran one-by-one in a single container
  2. No Caching: Dependencies downloaded on every run (~200MB)
  3. Unnecessary Tests: Some tests ran on every commit (even for documentation changes)
  4. Slow Selectors: XPath queries taking 2-5 seconds per element
  5. Network Delays: API calls without proper timeouts
  6. 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

MetricBeforeAfterImprovement
Total Pipeline Time45 min18 min60% faster
E2E Test Time28 min10 min64% faster
Setup Time8 min2 min75% faster
False Failure Rate15%2%87% reduction
Daily Pipeline Runs5050-
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:

  1. Predictive Test Selection: ML-based test prioritization based on code changes
  2. On-Demand Test Environments: Ephemeral preview environments for faster testing
  3. Visual Regression Testing: Parallel visual diff checks with Percy/Chromatic
  4. 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