DEV Community

Grafikui
Grafikui Subscriber

Posted on • Edited on

How I added carbon tracking to GitHub Actions (now with AWS, Azure, and GCP)

Updated March 2026: v0.5.x adds multi-cloud support (AWS + Azure + GCP), Scope 3 embodied carbon, water consumption tracking, inline PR suggestions, and policy budgets. Original post covered AWS-only v0.2.x.


Most carbon tracking tools are dashboards built for sustainability officers. They pull three-month-old billing data and produce a PDF. Engineers never see it.

This post is about shifting that left — into the pull request, before infrastructure is provisioned.

The problem with post-hoc measurement

By the time AWS's Carbon Footprint Tool tells you that your us-east-1 cluster emits twice as much as us-west-2 would have, it has been running for a quarter. The architecture is locked in, the carbon is burnt.

The only intervention point that changes what gets deployed is the PR.

What GreenOps CLI does

It's a GitHub Action that reads a terraform show -json plan output and posts a carbon and cost diff directly on the PR — across AWS, Azure, and GCP.

Here's what a developer sees on a multi-cloud plan:

🌱 GreenOps Infrastructure Impact

Metric                     | Monthly Total
Scope 2 — Operational CO2e | 12.27kg
Scope 3 — Embodied CO2e    | 3.13kg
Total Lifecycle CO2e       | 15.40kg
Water Consumption          | 12.8L
Infrastructure Cost        | $210.97/month

Potential Scope 2 Savings: -11.88kg CO2e/month (96.8%) | -$13.14/month
💡 Found 3 optimization recommendations.

Resource                           | Instance        | Region      | Scope 2 | Action
aws_instance.web                   | m5.large        | us-east-1   | 4.31kg  | UPGRADE
azurerm_linux_virtual_machine.api  | Standard_D2s_v3 | eastus      | 4.24kg  | UPGRADE
google_compute_instance.worker     | n2-standard-2   | us-central1 | 3.71kg  | UPGRADE
Enter fullscreen mode Exit fullscreen mode

No cloud credentials required. No outbound network calls from the CLI. The emission factors are a static JSON file you can read in ten minutes.

How the math works

Three dimensions are tracked per resource.

Scope 2 — Operational (CPU power × grid intensity):

W = W_idle + (W_max - W_idle) × utilisation
energy_kwh = W × PUE × 730h / 1000
co2e_g = energy_kwh × grid_intensity_gco2e_per_kwh
Enter fullscreen mode Exit fullscreen mode

PUE differs by provider: AWS 1.13, Azure 1.125, GCP 1.10.

Scope 3 — Embodied (hardware manufacturing, prorated):

embodied_g/month = (1,200,000g / 35,040h / 48 vCPUs) × vcpus × 730h
ARM discount: × 0.80  [Graviton, Ampere Altra, T2A]
Enter fullscreen mode Exit fullscreen mode

Water consumption (data centre cooling):

water_litres = (W × 730h / 1000) × WUE_litres_per_kwh
Enter fullscreen mode Exit fullscreen mode

For m5.large in us-east-1 at 50% utilisation, Scope 2 produces 4,313.57g CO2e/month. That value is asserted in engine.test.ts. You can verify it yourself from factors.json in under five minutes.

The full methodology — every formula, every assumption, every data source — is in METHODOLOGY.md and MIT-licensed.

Adding it to your workflow

- name: Generate Terraform Plan
  run: |
    terraform init
    terraform plan -out=tfplan
    terraform show -json tfplan > plan.json

- name: GreenOps Carbon Lint
  uses: omrdev1/greenops-cli@v0
  with:
    plan-file: plan.json
    github-token: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Works with AWS, Azure, and GCP plans — provider is detected automatically from resource types.

Optional: inline suggestion comments

With post-suggestions: true, GreenOps posts a one-click committable suggestion directly on the instance_type / size / machine_type line in the PR diff:

- name: GreenOps Carbon Lint
  uses: omrdev1/greenops-cli@v0
  with:
    plan-file: plan.json
    github-token: ${{ secrets.GITHUB_TOKEN }}
    post-suggestions: true
Enter fullscreen mode Exit fullscreen mode

The developer clicks "Commit suggestion" and the change is applied without leaving the PR.

Optional: policy budgets

Add .greenops.yml to your repo root to block merges that exceed a carbon or cost threshold:

version: 1
budgets:
  max_pr_co2e_increase_kg: 10
  max_pr_cost_increase_usd: 500
fail_on_violation: true
Enter fullscreen mode Exit fullscreen mode

fail_on_violation: true exits with code 1. The merge is blocked. The PR comment shows which constraint was breached and by how much.

Current limitations

  • EC2, RDS, Azure VMs, and GCP Compute only. No Lambda, no ECS, no AKS.
  • 71 instance types across the three providers. Unsupported instances are flagged as ⚠ UNKNOWN rather than silently showing zero.
  • Provider alias regions may not resolve — affected resources skip with a known_after_apply reason.
  • Annual average grid intensity. No real-time marginal emissions.

All of the above are tracked in open issues.

Why open source the methodology

Every other tool in this space uses proprietary emission factors. That doesn't survive a CSRD audit where a compliance officer needs to trace exactly how a number was produced.

If you disagree with an assumption, open a PR and change it.

github.com/omrdev1/greenops-cli

Top comments (0)