$ ~/cicdcalculator

How to reduce CI/CD costs
./optimize --proven-strategies

Ten optimisation techniques that consistently cut CI/CD spend, ranked by impact-to-effort. Each comes with a typical savings range and a one-paragraph implementation note. Pick the top two or three for your stack and you'll usually halve your monthly CI bill in a sprint.

01

Cache dependencies aggressively

saves 20-50%

Most pipelines spend 40-70% of build time on npm install / pip install / gradle build. Cache the dependency directory and the lock file together. Restore on cache hit, install only on miss. Every major CI/CD platform has a built-in cache action. This is the highest-impact single change you can make.

02

Skip jobs when nothing changed

saves 20-40%

Use path filters (paths: in GitHub Actions, rules: changes: in GitLab CI) so backend-only commits don't trigger frontend tests, and docs commits don't trigger anything. On busy monorepos this single change often pays for the entire optimisation effort.

03

Run heavy jobs only on protected branches

saves 10-30%

Full integration tests, performance benchmarks, and Cypress runs don't need to fire on every PR commit. Restrict them to main, release branches, or scheduled cron jobs. PR checks become fast lint + unit tests; deeper runs happen on merge.

04

Use spot / preemptible instances for self-hosted runners

saves 60-80% on compute

Spot instances on AWS or preemptible VMs on GCP cost 60-80% less than on-demand. CI jobs are idempotent so reclamation is harmless: the agent dies, the orchestrator retries on a fresh instance. Just don't put long-running deploy steps on spot.

05

Right-size your runners

saves 15-30%

A 4-core runner finishing in 4 minutes can be cheaper than a 2-core finishing in 12. Time the trade-off, don't assume the cheap runner wins. CircleCI's resource_class, GitHub Actions' larger_runner labels, and GitLab CI's tags: all let you target specific machine sizes per job.

06

Split slow test suites across parallel runners

saves wall-clock 50-80%, billable similar

knapsack_pro, ts-jest --shard, pytest-split, CircleCI --split-by=timings: all let you carve a 30-minute test run into ten 3-minute parallel jobs. Total billable minutes stay similar but PR feedback latency drops dramatically. Faster feedback means fewer retries means fewer billable minutes overall.

07

Set artifact retention to days, not months

saves $5-50/month per repo

Default retention on GitHub Actions is 90 days. Most artifacts are useful for 7-14. Drop retention with retention-days: 7 in your workflow yaml. Multiply across repos and you're saving real storage cost, especially on the Free and Team plans where storage past the included quota is billed at $0.25/GB/month.

08

Reduce Docker image rebuild work

saves 10-25%

Use multi-stage Dockerfiles with deterministic layer ordering, push intermediate stages as cache to a registry, and pull them on subsequent builds. Tools like docker buildx with type=registry caching make this almost automatic. A 6-minute image rebuild becomes 30 seconds when layers are cached properly.

09

Move artefacts off platform-billed storage

saves $10-100/month

Most CI/CD platforms charge premium rates for artifact storage. Push large artefacts (tarballs, Docker images, video recordings of e2e runs) to S3 or GCS instead. Standard cloud storage is 10-100x cheaper than CI/CD platform-included storage past the free tier.

10

Set hard spending limits

saves the runaway-loop bill

Every platform supports a spending cap. Set one. A single misconfigured workflow that triggers on every push of every branch can rack up four-figure bills overnight. Spending limits won't stop bad workflows but they'll stop the invoice. GitHub Actions, GitLab CI, and CircleCI all support hard caps at the org level.

Suggested order of work

  1. 01. Set spending limits today. Five-minute job, prevents disaster.
  2. 02. Add caching to your slowest install step. Ship in a day.
  3. 03. Add path filters to skip irrelevant jobs. Half a day on a monorepo.
  4. 04. Move artifact retention from default to 7-14 days. Five-minute change.
  5. 05. Move heavy jobs off PR triggers. Few hours, big PR latency win.
  6. 06. Right-size runners using actual job timings. One-week measurement.
  7. 07. Evaluate self-hosted runners for hot paths. Only if you're past 50K minutes / month.

Related guides

Frequently Asked Questions

# click any question to expand

What's the single biggest CI/CD cost saving?>
Aggressive dependency caching. Most pipelines spend 40-70% of their time installing npm, pip, gradle, or apt packages. Properly configured caches drop that to seconds and cut billable build minutes by a third or more. Every major CI/CD platform has a built-in cache action; the impact-to-effort ratio is unbeatable.
Does test parallelism save money or cost more?>
It depends on the platform. On per-minute platforms (GitHub Actions, GitLab CI), parallelism cuts wall-clock time but doesn't change billable minutes; you're still paying for the same total compute. On credit-based platforms (CircleCI), parallelism is free if you stay within concurrency limits. Parallelism saves money when it allows you to use smaller machines that finish faster overall.
When should I move to self-hosted runners?>
When you cross 50,000 build minutes per month consistently and have an engineer who can spend 4-6 hours per month on operator tasks. Below that threshold the engineering time costs more than the per-minute fees. Hybrid setups (hosted for PR checks, self-hosted for big nightly jobs) often beat pure-cloud or pure-self-hosted on cost.
How much do spot instances save?>
AWS Spot, Google preemptible, and Azure Spot VMs typically run 60-80% cheaper than on-demand. The trade-off is they can be reclaimed at any time. CI/CD jobs are an excellent fit because they're idempotent: a reclaimed agent retries on a new instance, costing one extra minute of compute. Pair with autoscaling to drop costs further during off-hours.
What's path-based filtering and is it worth it?>
Path-based filtering tells your CI to skip jobs when only certain files change. Backend-only PR? Skip the slow Cypress tests. Docs typo? Skip the entire pipeline. Worth a few hours of yaml work because it can cut billable minutes by 20-40% on a busy monorepo. Both GitHub Actions (paths:) and GitLab CI (rules: changes:) support it natively.
Should I split tests across runners?>
Yes if your test suite takes more than 10 minutes. Test splitting (using tools like ts-jest --shard, knapsack_pro, or CircleCI's --split-by=timings) divides tests across N parallel jobs. Wall-clock time drops to 1/N. On per-minute platforms total billable minutes stay roughly the same, but PR feedback latency goes from 30 minutes to 5, which is a real productivity win.