Cloud & DevOps

GitHub Actions: How I Cut Costs by 70%

December 26, 2024 2 min read By Amey Lokare

💰 The Problem

My GitHub Actions bill was $200/month. For a personal project. That's insane.

I had to do something. So I analyzed my workflows, found the waste, and cut costs by 70%.

The result: From $200/month to $60/month. Same functionality. Better performance.

📊 Where the Money Was Going

I analyzed my GitHub Actions usage:

Workflow Minutes/Month Cost
CI Tests (Linux) 1,200 $60
CI Tests (Windows) 800 $80
CI Tests (macOS) 600 $60

Total: 2,600 minutes/month = $200

❌ What Was Wasteful

1. Running Tests on Every Push

I was running full test suites on every push, even for documentation changes.

2. Testing on All Platforms

I was testing on Linux, Windows, and macOS for every change. Most of my code is platform-agnostic.

3. Long-Running Jobs

Some jobs took 20+ minutes when they should have taken 5.

4. No Caching

I wasn't caching dependencies, so every run downloaded everything from scratch.

✅ Optimizations That Worked

1. Conditional Workflows

Only run tests when code changes:

# .github/workflows/test.yml
on:
  push:
    paths:
      - 'app/**'
      - 'tests/**'
      - 'composer.json'
  pull_request:
    paths:
      - 'app/**'
      - 'tests/**'

Impact: Reduced runs by 40%. Saved $80/month.

2. Matrix Strategy Optimization

Only test on Linux for most changes, full matrix for releases:

# Test on Linux only for PRs
strategy:
  matrix:
    os: [ubuntu-latest]
    php: [8.2]

# Full matrix only for releases
if: github.event_name == 'release'
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    php: [8.1, 8.2, 8.3]

Impact: Reduced test runs by 60%. Saved $120/month.

3. Dependency Caching

Cache Composer and NPM dependencies:

- name: Cache Composer dependencies
  uses: actions/cache@v3
  with:
    path: vendor
    key: composer-${{ hashFiles('composer.lock') }}

- name: Cache NPM dependencies
  uses: actions/cache@v3
  with:
    path: node_modules
    key: npm-${{ hashFiles('package-lock.json') }}

Impact: Reduced job time by 50%. Saved $40/month.

4. Parallel Jobs

Run tests in parallel instead of sequentially:

jobs:
  test-unit:
    # Unit tests
  test-integration:
    # Integration tests
  test-e2e:
    # E2E tests

Impact: Faster feedback, same cost.

📊 Final Results

Metric Before After Savings
Minutes/Month 2,600 780 70%
Cost/Month $200 $60 $140
Average Job Time 12 min 6 min 50% faster

💡 Key Optimizations

  1. Conditional workflows: Only run when needed
  2. Smart matrix strategy: Full testing only when necessary
  3. Dependency caching: Reuse dependencies between runs
  4. Parallel jobs: Run tests concurrently
  5. Job timeouts: Kill jobs that run too long

🎯 Key Takeaways

  • GitHub Actions costs can add up quickly
  • Most workflows are wasteful by default
  • Simple optimizations can cut costs significantly
  • Conditional workflows are your friend
  • Caching is essential for cost savings

I went from $200/month to $60/month with these optimizations. The workflows are actually faster now, too. Win-win.

Comments

Leave a Comment

Related Posts