13 Billing und Quotas

Die Währung von GitHub Actions sind Minutes – ein Begriff, der irreführend einfach klingt. Eine Minute auf einem Linux-Runner ist tatsächlich eine Minute Rechenzeit. Auf einem macOS-Runner hingegen konsumiert dieselbe 60-Sekunden-Ausführung zehn Minutes aus dem Kontingent. Diese Multiplier-Logik verwandelt die Kostenrechnung in eine mehrdimensionale Gleichung, bei der Betriebssystem, Parallelität und Workflow-Dauer zusammenwirken.

Hinzu kommt ein differenziertes System aus Freibetragen, Limits und Abrechnungsregeln, das sich je nach GitHub-Plan unterscheidet. Public Repositories erhalten unlimitierte kostenlose Ausführungszeit, private Repositories hingegen unterliegen strikten Quotas. Wer diese Mechanismen nicht durchschaut, erlebt beim Monatsabschluss böse Überraschungen – besonders dann, wenn Matrix-Builds mit mehreren Betriebssystemen zum Einsatz kommen.

13.1 Minutes und das Multiplier-System

GitHub unterscheidet drei Runner-Typen mit unterschiedlichen Abrechnungsfaktoren:

Runner-Typ Multiplier Effektive Kosten pro Echtzeit-Minute Minute bei 60s Ausführung
Linux (Ubuntu) 1x $0.008 1 Minute
Windows 2x $0.016 2 Minutes
macOS 10x $0.080 10 Minutes

Ein Workflow, der auf allen drei Betriebssystemen jeweils fünf Minuten läuft, verbraucht nicht etwa 15 Minutes, sondern:

Linux:   5 Minuten × 1 = 5 Minutes
Windows: 5 Minuten × 2 = 10 Minutes
macOS:   5 Minuten × 10 = 50 Minutes
──────────────────────────────────────
Gesamt:               65 Minutes

Bei einem Free-Account mit 2.000 inkludierten Minutes pro Monat wären nach 31 solcher Workflow-Runs bereits 2.015 Minutes verbraucht – das Budget ist erschöpft.

Die Multiplier reflektieren die unterschiedlichen Infrastrukturkosten: Linux-Runner nutzen günstige x86-Hardware, macOS-Runner hingegen benötigen teure Mac-Hardware mit speziellen Lizenzanforderungen. Windows liegt preislich dazwischen, teilweise durch Lizenzkosten bedingt.

Die Abrechnung erfolgt auf volle Minuten aufgerundet. Ein Job, der 3 Minuten und 12 Sekunden läuft, wird als 4 Minuten berechnet. Bei macOS bedeutet das: 4 Minuten Laufzeit = 40 verbrauchte Minutes. Diese Rundungslogik summiert sich schnell bei vielen kurzen Jobs.

Ein typisches Anti-Pattern: Ein Entwickler richtet einen Test-Workflow auf macOS ein, der bei jedem Push läuft. Der Workflow dauert nur 2 Minuten, läuft aber 50-mal täglich. Das ergibt 100 Echtzeit-Minuten pro Tag, aber 1.000 verbrauchte Minutes – die Hälfte des Free-Kontingents für einen einzigen Workflow.

13.2 Plan-abhängige Kontingente

Die inkludierten Minutes variieren erheblich zwischen den GitHub-Plänen:

Plan Minutes/Monat Storage Cache Preis
Free 2.000 500 MB 10 GB/Repo $0
Pro 3.000 1 GB 10 GB/Repo $4
Team 3.000 2 GB 10 GB/Repo $4/User
Enterprise Cloud 50.000 50 GB 10 GB/Repo Custom

Wichtig: Diese Kontingente gelten pro Account, nicht pro Repository. Ein User mit zehn privaten Repositories teilt sich 2.000 Minutes über alle Repositories hinweg. Das kann problematisch werden, wenn ein Repository intensiv CI/CD betreibt und die anderen dadurch ausgehungert werden.

Die Minutes werden monatlich auf Null zurückgesetzt. Ungenutzte Minutes verfallen – es gibt kein Roll-over. Ein strategischer Fehler ist deshalb, am Monatsanfang sparsam zu sein und am Monatsende großzügig zu builden. Besser: Gleichmäßige Verteilung über den Monat.

Public Repositories haben eine Sonderstellung: Sie erhalten unlimitierte kostenlose Minutes für Standard-Runner. Dies gilt jedoch nicht für Larger Runner (4+ vCPUs), die auch bei Public Repos kostenpflichtig sind. Ein Open-Source-Projekt kann also kostenlos auf ubuntu-latest bauen, zahlt aber für ubuntu-latest-4-cores.

Überschreitet ein Account sein Kontingent, blockiert GitHub weitere Workflow-Runs – es sei denn, eine Zahlungsmethode ist hinterlegt. Dann beginnt die Abrechnung zusätzlicher Minutes zu den oben genannten Per-Minute-Raten. Ohne Zahlungsmethode laufen keine Workflows mehr, bis der nächste Monat beginnt.

13.3 Spending Limits und Kostenkontrolle

GitHub implementiert ein Spending-Limit-System, um unerwartete Rechnungen zu verhindern. Standardmäßig ist das Limit auf $0 gesetzt – sobald die inkludierten Minutes aufgebraucht sind, stoppen alle Workflows.

Diese harte Grenze lässt sich unter SettingsBilling and plansSpending limits anpassen. Werte zwischen $0 und unbegrenzt sind möglich. Ein Limit von beispielsweise $50 erlaubt Workflows, bis zusätzliche Kosten von $50 entstanden sind, dann stoppt die Ausführung wieder.

Ein praktisches Szenario: Ein Startup mit Team-Plan (3.000 inkludierte Minutes) setzt ein Spending Limit von $100. Die Minutes reichen für normale Entwicklung, aber intensive Feature-Branches mit vielen Matrix-Builds können das Budget überschreiten. Das $100-Limit gibt einen Puffer von:

$100 ÷ $0.008 = 12.500 zusätzliche Linux-Minutes
oder
$100 ÷ $0.016 = 6.250 zusätzliche Windows-Minutes
oder
$100 ÷ $0.080 = 1.250 zusätzliche macOS-Minutes

Ein häufiges Missverständnis: Das Spending Limit gilt pro Abrechnungsperiode, nicht pro Workflow oder Repository. Mehrere Repositories können das gemeinsame Limit aufbrauchen.

Für Organisationen existiert eine zusätzliche E-Mail-Benachrichtigung bei 75%, 90% und 100% Kontingentverbrauch. Diese Schwellenwerte sind nicht konfigurierbar, geben aber rechtzeitig Warnung vor einer Workflow-Blockade.

13.4 Matrix-Builds und exponentielle Kostenentwicklung

Matrix-Strategien generieren multiple Jobs aus einer einzigen Definition. Ein simples Beispiel:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [16, 18, 20]

Dieser Matrix-Build erzeugt 3 × 3 = 9 Jobs. Läuft jeder Job 10 Minuten, entstehen:

Ubuntu: 3 Jobs × 10 Min × 1 = 30 Minutes
Windows: 3 Jobs × 10 Min × 2 = 60 Minutes
macOS: 3 Jobs × 10 Min × 10 = 300 Minutes
────────────────────────────────────────
Gesamt:                      390 Minutes

Ein einzelner Workflow-Run verbraucht fast 20% des Free-Kontingents. Bei fünf Runs pro Tag (durchaus realistisch bei aktivem Development) sind 2.000 Minutes innerhalb einer Woche aufgebraucht.

Die Kosten skalieren nicht linear, sondern multiplikativ. Erweitert man die Matrix um Python-Versionen:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node: [16, 18, 20]
    python: [3.9, 3.10, 3.11]

Jetzt entstehen 3 × 3 × 3 = 27 Jobs. Die Minutes-Rechnung explodiert:

27 Jobs, davon:
- 9 auf Ubuntu: 9 × 10 × 1 = 90 Minutes
- 9 auf Windows: 9 × 10 × 2 = 180 Minutes
- 9 auf macOS: 9 × 10 × 10 = 900 Minutes
─────────────────────────────────────────
Gesamt:                       1.170 Minutes

Ein einzelner Run verbraucht über die Hälfte des Free-Kontingents. Das ist die exponentielle Falle von Multi-Dimensional-Matrices.

Die Lösung liegt in gezielter Matrix-Reduktion. Statt alle Kombinationen zu testen, fokussiert man auf relevante:

strategy:
  matrix:
    include:
      - os: ubuntu-latest
        node: 20
        python: 3.11
      - os: windows-latest
        node: 18
        python: 3.10
      - os: macos-latest
        node: 16
        python: 3.9

Dies erzeugt nur 3 Jobs statt 27 – eine 90%-Reduktion. Die Abdeckung bleibt ausreichend: Jedes OS, jede Node-Version und jede Python-Version wird getestet, nur nicht in jeder Kombination.

Eine weitere Strategie: macOS-Tests auf kritische Workflows beschränken. Pull-Request-Checks laufen nur auf Linux, Nightly-Builds zusätzlich auf Windows und macOS. Dies balanciert Kosteneffizienz mit Testabdeckung.

13.5 Parallelität und Concurrency-Limits

Die Minutes sind nur eine Dimension der Kostenkontrolle. Concurrency-Limits beschränken, wie viele Jobs gleichzeitig laufen können:

Plan Standard Runner macOS Larger Runner
Free 20 5 N/A
Pro 40 5 N/A
Team 60 5 1.000
Enterprise 500 50 1.000

Diese Limits sind Account-weit. Ein Free-Account kann maximal 20 Jobs parallel ausführen, unabhängig von der Anzahl Repositories oder Workflows.

Ein 27-Jobs-Matrix-Build trifft auf das 20-Jobs-Limit eines Free-Accounts: 20 Jobs starten sofort, 7 warten in der Queue. Sobald ein Job endet, startet der nächste. Die Gesamtlaufzeit verlängert sich dadurch:

Ohne Limit: 27 Jobs parallel = 10 Minuten
Mit Limit: 20 + 7 sequenziell = ~14 Minuten

Die Wartezeit zählt nicht als verbrauchte Minutes – GitHub berechnet nur tatsächliche Ausführungszeit. Dennoch entstehen indirekte Kosten durch verzögerte Feedback-Zyklen.

macOS hat zusätzlich ein dediziertes Limit von 5 concurrent Jobs (außer Enterprise mit 50). Ein großer Matrix-Build mit 9 macOS-Jobs kann also nur 5 parallel ausführen, die restlichen 4 müssen warten. Dies verlängert die Durchlaufzeit dramatisch, wenn macOS der Flaschenhals ist.

Larger Runner haben separate Limits (Team/Enterprise: 1.000). Ein Workaround für Concurrency-Bottlenecks ist daher der Umstieg auf Larger Runner – allerdings zu höheren Kosten, da inkludierte Minutes dort nicht gelten.

Die Concurrency kann auch absichtlich limitiert werden, etwa für Deployment-Workflows:

concurrency:
  group: production-deploy
  cancel-in-progress: false

Dies garantiert, dass nur ein Deployment gleichzeitig läuft, unabhängig vom Account-Limit. Nützlich, um Race Conditions bei Deployments zu vermeiden, hat aber keine direkten Kostenauswirkungen.

13.6 Cache Storage und Artifact Retention

Neben Minutes fallen Kosten für Storage an. GitHub unterscheidet zwei Arten:

Artifacts sind Build-Outputs: Kompilierte Binaries, Test-Reports, Coverage-Daten. Die Retention-Periode ist konfigurierbar (1-400 Tage je nach Plan), Standard sind 90 Tage. Storage-Kosten: $0.25/GB pro Monat.

Caches sind Zwischenspeicher für Dependencies: node_modules, Maven-Repositories, Docker-Layer. Pro Repository sind 10 GB kostenlos, darüber hinaus $0.07/GiB pro Monat.

Ein typisches Node.js-Projekt cachet node_modules mit ~500 MB. Bei 10 aktiven Feature-Branches entstehen 5 GB Cache-Usage – innerhalb des Freibetrags. Kommen weitere 20 Branches hinzu, wächst der Cache auf 15 GB. Die zusätzlichen 5 GB kosten $0.35 pro Monat – vernachlässigbar.

Artifacts hingegen akkumulieren schnell: Ein Build erzeugt 200 MB Artifacts (Binary + Source Maps + Tests). Bei täglichen Builds sind das 6 GB pro Monat. Nach 90 Tagen Retention: 180 GB gespeichert = $45/Monat nur für Artifacts.

Die Lösung: Aggressive Retention-Policies. Artifacts für Pull Requests benötigen nur 7-Tage-Retention, nicht 90. Produktions-Releases hingegen sollten länger aufbewahrt werden. Dies konfiguriert man per Workflow:

- uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/
    retention-days: 7

Für Cache existiert eine automatische LRU-Eviction: Wird das 10-GB-Limit erreicht, löscht GitHub die am längsten ungenutzten Caches. Ein inaktiver Feature-Branch verliert seinen Cache nach ~7 Tagen Inaktivität (konfigurierbar bis 365 Tage).

Ein optimales Cache-Management nutzt key und restore-keys intelligent:

- uses: actions/cache@v4
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Dies erstellt einen Cache pro OS und Lock-File-Hash. Bei unverändertem package-lock.json wird der Cache wiederverwendet, bei Änderung ein neuer erstellt. Der alte Cache wird durch LRU-Eviction automatisch entfernt, wenn das Limit erreicht wird.

13.7 Realistische Kostenszenarien

Ein mittelgroßes Team (5 Entwickler, 10 private Repositories, Team-Plan) hat folgende Nutzung:

Kostenrechnung zusätzlicher Minutes:

Linux-Anteil (geschätzt 40%): 1.580 × $0.008 = $12.64
Windows-Anteil (geschätzt 20%): 790 × $0.016 = $12.64
macOS-Anteil (geschätzt 40%): 1.580 × $0.080 = $126.40
────────────────────────────────────────────────────
Gesamt:                                     $151.68

Hinzu kommen Storage-Kosten:

Artifacts: 120 GB × $0.25 = $30.00
Cache: 15 GB zusätzlich × $0.07 = $1.05
────────────────────────────────────────────
Gesamt:                         $31.05

Gesamtkosten: Team-Plan ($4 × 5 = $20) + Minutes ($151.68) + Storage ($31.05) = $202.73 pro Monat.

Optimierungsmaßnahmen könnten sein:

  1. macOS-Tests reduzieren: Nur kritische Workflows → -50% macOS = $63 gespart
  2. Artifact Retention kürzen: 30 statt 90 Tage → -67% Storage = $20 gespart
  3. Matrix-Builds optimieren: Gezielter statt vollständig → -30% Runs = $45 gespart

Nach Optimierung: $74.73 pro Monat – eine 64%-Reduktion.

Die Kernlektion: Minutes-Kosten sind beherrschbar, wenn man bewusst plant. Die teuersten Fehler sind unkontrollierte macOS-Matrix-Builds und lange Artifact-Retention ohne Notwendigkeit. Ein regelmäßiger Blick auf das Billing-Dashboard unter SettingsBilling and plansUsage this month zeigt, wo die Minutes hinfließen – und wo Optimierungspotential liegt.