← Back to Blog
DevOps

CI/CD Pipeline Optimization: Cutting Build Time by 20%

Feb 20266 min read

At PT Luna Aplikasi Indonesia, our Android CI pipeline was taking 15+ minutes per build. PRs were slow to merge and developers lost focus context switching while waiting. Here's how I cut that to under 12 minutes.

Step 1: Profile Before Optimizing

First, I timed each phase. Turns out 60% of time was spent on Gradle dependency downloads and compilation. Caching was either absent or misconfigured.

Step 2: Aggressive Dependency Caching

This single change cut 3–4 minutes per build. The key is caching both the Gradle wrapper and the actual dependency cache, keyed to your lockfile.

- name: Cache Gradle
  uses: actions/cache@v3
  with:
    path: |
      ~/.gradle/caches
      ~/.gradle/wrapper
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

Step 3: Parallel Jobs

Split unit tests, lint, and build into parallel jobs. Unit tests and lint don't depend on the build artifact — they can run concurrently.

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: ./gradlew lint

  test:
    runs-on: ubuntu-latest
    steps:
      - run: ./gradlew test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]   # Gate release on quality checks
    steps:
      - run: ./gradlew assembleRelease

Step 4: Build Configuration

  • Enable Gradle daemon and parallel execution in gradle.properties
  • Set org.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC for faster compilation
  • Use --build-cache flag to reuse outputs from previous builds

💡 Final result: 15:20 → 11:48 average build time (23% reduction). Extrapolated across the team's ~20 daily builds, that's ~1 hour of CI time saved per day.

Conclusion

CI optimization is high-leverage work — a few hours of setup pays dividends for the lifetime of the project. Start with caching, then parallelize, then profile remaining bottlenecks.