Software Development

Sustainable Software Engineering: Measuring and Reducing Your Code’s Carbon Footprint

Green software is no longer optional. From the SCI metric to JVM GC tuning, here’s how engineers can measure — and genuinely reduce — the carbon their code emits.

There’s a question engineers almost never ask when they merge a pull request: how much CO₂ did that just cost? For most of software history, that question didn’t even make sense. Code was abstract. Emissions were a hardware problem — data centres, cooling systems, physical infrastructure. The software just ran.

That framing is, unfortunately, no longer accurate. The information and communication technology sector currently contributes between 2.1% and 3.9% of global greenhouse gas emissions, and without meaningful action, projections suggest that figure could climb toward 14% of global emissions by 2040. Meanwhile, the International Energy Agency projects data-centre electricity consumption could double through 2030, driven largely by cloud workloads and AI training.

Consequently, green software engineering has shifted from a niche academic interest to a commercial and regulatory priority. Regulation is catching up fast. The EU’s Corporate Sustainability Reporting Directive (CSRD), which came into force in 2024, requires large companies to report Scope 3 software-related emissions. The Green Software Foundation’s SCI metric is now an ISO-accredited international standard. And Gartner predicts that by 2026, 50% of organisations will adopt sustainability-enabled cloud monitoring as a first-class operational metric.

In short: your code has a carbon footprint, you’ll likely be required to measure it soon, and the tools to do so already exist. This guide walks through all three layers — measurement tooling, the SCI standard, and the often-overlooked JVM angle that Java developers in particular can act on immediately.

Why software — not just hardware — is the problem

A common misconception is that a company’s carbon footprint in tech lives entirely in its hardware procurement decisions — chip manufacturing, server rack energy use, office HVAC. While those absolutely matter, the software layer is increasingly where leverage lives. As the Software Improvement Group’s CEO Luc Brandts puts it: “When you want to do things on sustainability in software, it is really about looking at the code.”

Poor coding standards, bloated system architecture, and energy-draining patterns like redundant loops, over-fetching from databases, and unnecessary object allocation directly drive up the wattage your servers consume. Furthermore, since software determines how efficiently hardware is utilised, two applications doing the same job on identical hardware can have radically different carbon outputs simply because of algorithmic choices and memory management strategies.

There are, moreover, three layers where software creates emissions. First, there’s the operational carbon — the ongoing electricity consumed while the software runs. Second, there’s the embodied carbon — the manufacturing and disposal footprint of the hardware your software demands. Third, and increasingly significant, there’s the carbon associated with AI workloads, where training a single large language model can emit as much CO₂ as five average cars over their entire lifetime. Software engineers make decisions that touch all three layers every day.

The distinction between operational carbon and embodied carbon matters for strategy. Operational carbon is reduced through efficient code, better algorithms, and smarter scheduling. Embodied carbon is reduced by extending hardware lifetime — which means writing software that doesn’t force hardware upgrades through excessive resource demands.

Measuring it: the SCI standard and what it actually tells you

Before you can reduce emissions, you need a consistent way to measure them. That’s precisely the gap the Software Carbon Intensity (SCI) specification was designed to fill. Developed by the Green Software Foundation, SCI became an ISO-accredited international standard — ISO/IEC 21031:2024 — in March 2024. It’s now the first internationally standardised method for calculating software carbon intensity, and it’s already being referenced in CSRD compliance frameworks across Europe.

The core insight of SCI is that it measures a rate, not a total. Traditional carbon accounting asks “how much did we emit?” SCI asks “how much do we emit per unit of useful work?” That rate-based framing is critical because it forces engineers to connect emissions to business value, and it creates a metric you can continuously improve.

The functional unit R is where teams have the most design freedom. A web service might define R as “per 1,000 API requests.” A batch processing pipeline might use “per GB of data processed.” A mobile app might target “per active user session.” The choice of R shapes what improvements you pursue, which is why the SCI specification deliberately leaves it open.

Importantly, SCI does not allow carbon offsets to lower your score. This is a deliberate design choice: the spec is specifically intended to drive real reductions through better engineering, not accounting manoeuvres. If you plant trees to offset your cloud bill, that’s fine for your GHG Protocol reporting, but your SCI score won’t budge. Only genuinely more efficient software improves the number.

The Green Software Foundation has published guidance showing how SCI maps directly to CSRD’s ESRS E1-6 (GHG emissions reporting) requirement. If your organisation is subject to CSRD, adopting SCI now gives you a head start on mandatory Scope 3 software emissions disclosure — and gives auditors a standardised, ISO-certified methodology to work with.

The tooling landscape: from CodeCarbon to Cloud Carbon Footprint

Standards and formulas are only as useful as the tools that make them practical. Fortunately, the green software tooling ecosystem has matured significantly over the past two years. Here’s a clear breakdown of the major players and where each one fits in a typical engineering workflow.

Getting started with CodeCarbon in three lines

For teams working in Python — whether that’s data science, ML pipelines, or backend services — CodeCarbon is arguably the lowest-friction entry point into carbon measurement. Installing and wrapping your code takes minutes. The following snippet installs the package and wraps a target function with a decorator that automatically outputs emissions to a emissions.csv file.

Shell — install CodeCarbon

pip install codecarbon

Python — decorator pattern (simplest integration)

from codecarbon import track_emissions

@track_emissions()
def run_pipeline():
    # Your compute-intensive function here
    # CodeCarbon samples CPU, GPU, and RAM power at fixed intervals
    # and multiplies by the regional carbon intensity of your grid
    pass

run_pipeline()
# Writes: emissions.csv with kWh consumed and kg CO₂ equivalent

Python — explicit tracker (for more control)

from codecarbon import EmissionsTracker

tracker = EmissionsTracker(project_name="data-ingestion-job", log_level="error")
tracker.start()

# --- your code block here ---

emissions = tracker.stop()
print(f"Emissions: {emissions:.6f} kg CO₂")

What makes CodeCarbon particularly useful is that it factors in where you’re computing, not just how much. A job running in a data centre powered by Norwegian hydropower will have a dramatically lower carbon intensity (gCO₂/kWh) than the same job running on a coal-heavy grid in parts of Central Asia. The tool queries regional grid data automatically and adjusts accordingly — a subtle but important detail that the SCI formula’s “I” variable captures directly.

It’s worth noting that tools like CodeCarbon produce estimates, not exact measurements. Research has shown that carbon estimation tools can differ from each other by a factor of roughly 2.4x for the same workload. The key is to use the same tool consistently over time and treat the numbers as relative indicators for improvement tracking, rather than precise absolute values.

The JVM angle: how GC tuning maps to energy consumption

Here’s where this article takes a turn that most green software guides skip entirely. For the large portion of the software industry running Java-based workloads — enterprise applications, Spring Boot microservices, Kafka consumers, Hadoop pipelines — the JVM’s garbage collector is one of the most direct levers for reducing energy consumption, and therefore carbon output.

The reason is straightforward. GC activity directly drives CPU utilisation. Every time the garbage collector runs, it consumes compute cycles that translate into watts drawn from the power grid. A poorly tuned GC that runs frequently, triggers long stop-the-world pauses, or forces full heap collections is not just slow — it’s also measurably more carbon-intensive than a well-tuned one.

G1GC, ZGC, and Shenandoah: the energy implications

Java’s three modern garbage collectors each have different CPU usage profiles and energy characteristics. As a general rule, collectors that do more work concurrently (without stopping application threads) will appear to use more CPU at any given moment but avoid the sharp spikes of stop-the-world events that cause both latency and energy bursts.

JVM GC Algorithm: CPU Overhead & GC Pause Comparison

Relative values — lower is better. Based on benchmark studies and Java 23 performance data. Sources: Java 23 GC comparison study (DEV Community)Datadog Java GC deep dive. Values are representative benchmarks.

The carbon insight here is nuanced. Parallel GC has the lowest average CPU overhead, which might seem most efficient — but its long stop-the-world pauses mean the JVM is periodically spiking to maximum CPU utilisation to complete collection as fast as possible. That creates energy peaks that are both expensive and hard to schedule around.

ZGC and Shenandoah, by contrast, spread GC work concurrently across time. The IPC (instructions per clock) profile is smoother, power draw is steadier, and there’s growing academic evidence — including a study on scheduling ZGC on energy-efficient cores — showing that concurrent collectors can reduce per-application energy consumption by around 11% without meaningful performance degradation when properly scheduled on heterogeneous processor architectures like Intel’s Alder Lake (P-core + E-core) chips.

Practical JVM flags for greener Java services

Beyond just choosing the right collector, several JVM tuning flags directly affect how much CPU work (and therefore energy) your application consumes over time. The following examples work on Java 17+ and are production-tested patterns.

Shell — GC selection and heap sizing for a 4GB Spring Boot service

# Use ZGC for latency-sensitive services on Java 21+ (generational mode)
java -XX:+UseZGC -XX:+ZGenerational \
     -Xms2g -Xmx4g \
     -XX:ConcGCThreads=2 \
     -jar your-service.jar

# Use G1GC for throughput-oriented batch jobs (default since Java 9)
java -XX:+UseG1GC \
     -Xms4g -Xmx4g \
     -XX:MaxGCPauseMillis=200 \
     -XX:G1HeapRegionSize=8m \
     -XX:ParallelGCThreads=4 \
     -XX:ConcGCThreads=2 \
     -jar your-batch-job.jar

If your service runs in a container with less than 4–6 GB of RAM, think carefully before reaching for ZGC. It typically requires 25–35% free heap headroom to operate correctly. In memory-constrained containers (under 4GB), G1GC will often be more energy-efficient because it won’t risk allocation stalls that force full GC cycles under memory pressure.

JVM energy reduction: a comparison summary

OptimisationJava VersionEnergy impactBest for
Switch to ZGC (generational)Java 21+ / 23+Smoother CPU draw, less energy spikingLatency-sensitive microservices
Set equal Xms/Xmx in prodAllEliminates costly heap resize operationsAll services
Reduce GC thread countAllLowers peak CPU during GC cyclesMulti-service hosts
Use Virtual Threads (Loom)Java 21+Reduces threads-per-request overheadHigh-concurrency APIs
Enable GraalVM Native ImageJava 17+Eliminates JVM warm-up energy costShort-lived CLI / serverless
Tune MaxGCPauseMillisG1GC / Java 9+Prevents oversized collection eventsGeneral-purpose services

Carbon-aware architecture: shifting when and where you compute

Beyond optimising how your code runs, there’s a second, often larger lever: controlling when and where it runs. This is the domain of carbon-aware computing — a concept that’s moved from research paper to practical tooling over the past two years.

The principle is simple. Electricity grids have different carbon intensities at different times of day and in different geographic regions, depending on how much renewable energy is in the mix at any given moment. Running a batch job at 2am when wind and solar are peaking in your region can produce dramatically fewer emissions than running the same job at peak demand hours when fossil fuel plants are spinning up to meet demand.

The Green Software Foundation’s Carbon-Aware SDK and the Electricity Maps API make this queryable in real time. Furthermore, all three major cloud providers now offer tools to select regions based on carbon intensity — and with AWS, GCP, and Azure all publishing sustainability data through APIs, it’s increasingly feasible to build carbon-aware deployment pipelines that automatically prefer greener regions for flexible workloads.

Carbon Intensity by Cloud Region: Representative Values

gCO₂eq per kWh — lower means cleaner electricity. Sample of major cloud regions, approximate 2024–2025 values. Sources: Electricity Maps; cloud provider sustainability reports. Values are illustrative averages — actual intensity varies by hour and season.

The implication for architects is significant. If your application’s primary compute load is in a region running on a carbon-heavy grid, and if that load is flexible (batch jobs, model training, data exports, report generation), then migrating or scheduling those workloads to cleaner regions can reduce their carbon footprint by a factor of 2 to 10 — without changing a single line of application code.

Where to start: a practical green engineering checklist

The breadth of green software can feel overwhelming at first. However, rather than trying to solve everything at once, the most effective approach is to focus on the highest-leverage actions first. Here’s a practical prioritisation, roughly ordered from lowest effort to highest impact:

ActionEffortImpactTooling
Add CodeCarbon to ML / batch pipelinesLow (minutes)Measurement baselineCodeCarbon
Connect Cloud Carbon Footprint to AWS/GCP/AzureLow–MediumCloud visibilityCloud Carbon Footprint
Tune JVM GC for your workload profileMediumMedium–High (CPU reduction)JVM flags, GC logs
Shift batch jobs to low-carbon time windowsMediumHigh (2–10× carbon reduction)Carbon-Aware SDK
Calculate your first SCI scoreMediumStrategic — enables improvement trackingGSF Impact Framework
Migrate flexible workloads to green-grid regionsHighVery HighElectricity Maps + cloud APIs
Optimise algorithms for compute efficiencyHighHighest (foundational)Profiling + SCI tracking

The single most important first step is simply to measure. As the CodeCarbon team puts it — echoing Niels Bohr — “nothing exists until it is measured.” Once you have a baseline SCI score or a CodeCarbon emissions log, every architectural and code-level decision can be evaluated against a concrete number. That changes the conversation in engineering teams from vague sustainability intentions to something that behaves like any other performance metric: tracked, graphed, and improved over time.

What we’ve covered

This article explored sustainable software engineering from measurement standards all the way down to JVM flags — here’s the full picture in brief:

  • The ICT sector accounts for 2–4% of global greenhouse gas emissions today, with projections pointing toward 14% by 2040 if current growth trajectories continue unchecked.
  • The Green Software Foundation’s SCI metric — now ISO/IEC 21031:2024 — provides a rate-based carbon intensity score per functional unit (per transaction, per API call) that offsets cannot artificially lower, driving real engineering improvements.
  • CodeCarbon is the most accessible entry point for Python-based teams: three lines of code can start producing per-experiment emissions logs that map energy consumption to regional carbon intensity.
  • For Java teams, JVM garbage collector choice and tuning is a direct lever on energy consumption — ZGC’s concurrent model produces smoother CPU draw and measurably lower energy spikes compared to stop-the-world collectors, especially on Java 21+ with generational mode.
  • Carbon-aware scheduling — shifting flexible compute to low-carbon grid windows or cleaner cloud regions — can reduce workload emissions by 2–10× without changing any application code.
  • Green software is moving from voluntary to mandatory: CSRD now requires Scope 3 software emissions reporting for large EU-exposed companies, and SCI maps directly to ESRS E1-6 compliance needs.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button