7 Ways Your CI/CD Pipeline is Wasting Money

7 Ways Your CI/CD Pipeline is Wasting Money

CI/CD isn’t free. Every pipeline run costs money in compute time.

After auditing pipelines for 20+ teams, here are the 7 most common sources of waste – and how to fix them.

1. Running Expensive Compute for Simple Tasks

The waste: Using large CI runners for trivial jobs like linting or markdown checks.

Real example: GitHub Actions workflow running on ubuntu-latest-8-cores runner for ESLint.

ESLint job takes 45 seconds. Using 8-core runner when 2-core would work fine.

Cost:
8-core runner: £0.064/minute
2-core runner: £0.008/minute
Waste: £0.056/minute × 45 seconds = £0.042 per run

With 200 commits/month: £8.40/month wasted on one job.

Fix: Right-size runners per job:

jobs:
  lint:
    runs-on: ubuntu-latest  # 2-core, cheap
    steps:
      - run: npm run lint

  tests:
    runs-on: ubuntu-latest-4-cores  # Tests need more power
    steps:
      - run: npm test

  e2e:
    runs-on: ubuntu-latest-8-cores  # E2E tests are heavy
    steps:
      - run: npm run test:e2e

2. Rebuilding Dependencies Every Time

The waste: Downloading and installing npm/pip/maven packages from scratch on every run.

Real example: Node.js project with 300MB of node_modules.

Every CI run:

  • Download packages: 2 minutes
  • Install packages: 3 minutes
  • 5 minutes of waste per run at £0.008/min = £0.04

200 runs/month = £8/month + 16.6 hours of engineer wait time

Fix: Cache dependencies:

- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

- name: Install dependencies
  run: npm ci

Now installation takes 15 seconds instead of 5 minutes.

3. Running Tests You Don’t Need

The waste: Running entire test suite when only documentation changed.

Real example: Pull request updating README.md triggers:

  • Unit tests: 8 minutes
  • Integration tests: 12 minutes
  • E2E tests: 15 minutes
  • Total: 35 minutes of compute for a markdown file change

Cost: 35 minutes × £0.008/min = £0.28 per documentation PR

With 50 documentation changes/month: £14/month waste

Fix: Use path filters:

on:
  pull_request:
    paths-ignore:
      - '**.md'
      - 'docs/**'
      - 'LICENSE'
      - '.gitignore'

# Or run only specific tests based on changed files
- name: Run unit tests
  if: contains(github.event.pull_request.changed_files, 'src/')
  run: npm run test:unit

4. Not Failing Fast

The waste: Running expensive tests when quick checks already failed.

Real example: Pipeline structure:

  1. Linting (1 min) – FAILS
  2. Unit tests (8 min) – runs anyway
  3. Integration tests (12 min) – runs anyway
  4. E2E tests (15 min) – runs anyway

Developer pushes code with linting errors. Pipeline runs for 36 minutes before showing failure.

Cost: 35 wasted minutes × £0.008 = £0.28 per failed run

With 100 failed builds/month: £28/month waste + terrible developer experience

Fix: Order jobs by speed, make later jobs depend on earlier ones:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    needs: lint  # Only run if lint passes
    runs-on: ubuntu-latest-4-cores
    steps:
      - run: npm test

  e2e:
    needs: test  # Only run if tests pass
    runs-on: ubuntu-latest-8-cores
    steps:
      - run: npm run test:e2e

Now pipeline fails in 1 minute instead of 36 minutes.

5. Duplicate Docker Builds

The waste: Building the same Docker image multiple times per deployment.

Real example: Pipeline that:

  1. Builds image for testing
  2. Runs tests
  3. Builds image again for production (identical)
  4. Pushes to registry

Each build takes 12 minutes. Building twice = 12 minutes wasted per deployment.

Cost: 12 minutes × £0.032/min (4-core runner) = £0.384 per deployment

50 deployments/month = £19.20/month waste

Fix: Build once, test the image, then tag and push:

- name: Build Docker image
  run: docker build -t myapp:${{ github.sha }} .

- name: Run tests in container
  run: docker run myapp:${{ github.sha }} npm test

- name: Tag for production
  run: docker tag myapp:${{ github.sha }} myapp:latest

- name: Push to registry
  run: docker push myapp:latest

6. Running CI on Every Branch

The waste: Full CI pipeline runs on experimental feature branches that never get merged.

Real example: Team creates 50 branches/month. Only 20 get merged.

30 abandoned branches × 35 minutes of CI = 1,050 minutes wasted

Cost: 1,050 minutes × £0.008 = £8.40/month on branches that never ship

Fix: Run full pipeline only on important branches:

on:
  push:
    branches:
      - main
      - develop
      - 'release/**'
  pull_request:
    types: [opened, synchronize, reopened]

# For feature branches, run lightweight checks only
jobs:
  quick-check:
    if: github.ref != 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint
      - run: npm run test:unit

  full-pipeline:
    if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request'
    # ... full test suite

7. No Automatic Cleanup of Old Artifacts

The waste: Storing build artifacts, Docker images, and logs forever.

Real example: Company storing:

  • GitHub Actions artifacts: 90 days retention (default)
  • Docker images in ECR: never deleted
  • CI logs: stored indefinitely

Storage costs:
GitHub Actions artifacts: £0.008/GB/day
ECR images: £0.10/GB/month
CloudWatch logs: £0.03/GB/month

After 2 years:

  • 500GB of old artifacts
  • 200GB of Docker images (10 images per day × 730 days)
  • 100GB of logs

Monthly cost:
Artifacts: £120
ECR: £20
Logs: £3
Total: £143/month for old data nobody uses

Fix: Implement retention policies:

# GitHub Actions - set artifact retention
- uses: actions/upload-artifact@v3
  with:
    retention-days: 7  # Only keep for 1 week

# ECR lifecycle policy
{
  "rules": [{
    "rulePriority": 1,
    "description": "Keep only 10 images",
    "selection": {
      "tagStatus": "any",
      "countType": "imageCountMoreThan",
      "countNumber": 10
    },
    "action": { "type": "expire" }
  }]
}

# CloudWatch logs retention
aws logs put-retention-policy 
  --log-group-name /aws/ci-builds 
  --retention-in-days 30

The Total Waste

Add up all 7 sources of waste:

Waste Source Monthly Cost
Oversized runners £8.40
No dependency caching £8.00
Unnecessary test runs £14.00
Not failing fast £28.00
Duplicate Docker builds £19.20
CI on unused branches £8.40
No artifact cleanup £143.00
Total £229/month

Over a year: £2,748 wasted on CI/CD inefficiency

And this is for a single project. Multiply by number of repos…

How We Optimize CI/CD Pipelines

Our Infrastructure Audit includes CI/CD pipeline review:

  • Analyze all GitHub Actions / GitLab CI / CircleCI workflows
  • Identify waste and bottlenecks
  • Implement caching and optimization
  • Configure proper artifact retention
  • Set up cost monitoring

Typical results:

  • 40-60% reduction in CI costs
  • 50%+ faster build times
  • Better developer experience

Cost: £3,000 (2-week audit + implementation)

Savings: £200-400/month (ROI in ~10 months)

Book a Discovery Call

We’ll review your CI/CD setup and estimate potential savings.