Dependency-Updates ohne Drama: Renovate, Dependabot und eine Routine

Wer Abhängigkeiten ein Jahr liegen lässt, zahlt mit einem Wochenende voller Breaking Changes. So hältst du Updates klein und regelmäßig.

WartungToolingSicherheit
Dependency-Updates ohne Drama: Renovate, Dependabot und eine Routine

Dependency-Updates werden nicht schwer, weil sie kompliziert sind. Sie werden schwer, weil man sie liegen lässt. Wer kleine Updates automatisiert und regelmäßig einspielt, hat selten Ärger. Wer einmal im Jahr alles auf einmal anfasst, verbringt ein Wochenende mit Fehlern, die sich gegenseitig überlagern.

Warum „läuft doch“ keine Strategie ist

In fast jedem Projekt, das ich übernommen habe, sah die package.json gleich aus: Versionen von vor zwei Jahren, ein paar Pakete mit bekannten Sicherheitslücken, und irgendwo ein Kommentar à la „nicht updaten, bricht sonst X“. Niemand wusste mehr genau, was eigentlich bricht.

Das Problem ist nicht das einzelne veraltete Paket. Das Problem ist der Zinseszins. Framework-Version A braucht Build-Tool B mindestens in Version soundso, das wiederum eine neuere Node-Version voraussetzt, die dein Hoster erst nach einem Umzug anbietet. Aus einem Update werden fünf, die nur gemeinsam funktionieren. Und wenn dann ein Test rot wird, weißt du nicht, welche der fünf Änderungen schuld ist.

Kleine, häufige Updates lösen das. Jede Änderung ist isoliert, jeder Fehler hat genau einen Verdächtigen.

Die Werkzeuge: Dependabot und Renovate

Für die Automatisierung gibt es im Wesentlichen zwei etablierte Bots. Beide lesen deine Manifest- und Lockfiles, erkennen neue Versionen und öffnen Pull Requests.

Dependabot ist direkt in GitHub eingebaut. Du legst eine .github/dependabot.yml an, gibst Paket-Ökosystem und Intervall an, fertig. Dazu kommen die Sicherheitswarnungen, die GitHub auch ohne diese Datei anzeigt. Der Vorteil: kein zusätzlicher Dienst, schnell eingerichtet. Der Nachteil: weniger Stellschrauben, und außerhalb von GitHub nicht nutzbar.

Renovate läuft auf GitHub, GitLab, Bitbucket und weiteren Plattformen, als gehosteter App-Dienst oder selbst betrieben. Es ist deutlich konfigurierbarer: Gruppierung von Paketen, Zeitfenster, Automerge nach Regeln, ein „Dependency Dashboard“ als Issue mit dem Überblick über alle offenen Updates. Der Preis dafür ist eine Konfiguration, die schnell unübersichtlich wird, wenn man jede Option ausprobiert.

Meine ehrliche Empfehlung: Wenn dein Code auf GitHub liegt und du bisher gar nichts automatisierst, fang mit Dependabot an. Wenn dich nach ein paar Wochen die Flut an Einzel-PRs nervt, ist das der Moment, auf Renovate umzusteigen oder bei Dependabot die Gruppierung zu nutzen, die es inzwischen ebenfalls kann.

Der eigentliche Hebel: PR-Flut bändigen

Der Grund, warum viele Teams Update-Bots nach kurzer Zeit wieder abschalten, ist nicht technisch. Es ist die Menge. Ein mittelgroßes JavaScript-Projekt hat schnell mehrere hundert transitive Abhängigkeiten, und plötzlich stehen montags zwanzig offene PRs im Repo.

Drei Maßnahmen machen das erträglich:

Gruppieren

Pakete, die zusammengehören, sollten in einem PR landen. Alle @types/*-Pakete, alle ESLint-Plugins, alle Pakete eines Frameworks. Das reduziert die Zahl der PRs und verhindert, dass du halbe Updates einspielst, bei denen Kernpaket und Plugin nicht zueinander passen.

Zeitfenster setzen

Lass den Bot nicht rund um die Uhr PRs öffnen. Ein fester Termin – bei mir Montagvormittag – macht Updates zu einer planbaren Aufgabe statt zu einem Dauerrauschen. Sicherheitsupdates sind die Ausnahme, die dürfen sofort kommen.

Automerge für das Langweilige

Patch-Updates von Dev-Dependencies, die grüne Tests haben, musst du nicht händisch anklicken. Wenn deine CI verlässlich ist, lass sie automatisch mergen. Das ist der Punkt, an dem sich eine vernünftige Testabdeckung direkt auszahlt – und an dem sich zeigt, ob du ihr wirklich vertraust.

Automerge für Major-Versionen oder für Laufzeit-Abhängigkeiten in Produktion würde ich dagegen nicht einschalten. Dort gehören Changelog lesen und kurz manuell testen dazu.

Semver ist ein Versprechen, keine Garantie

Die ganze Automatisierung stützt sich auf Semantic Versioning: Patch-Versionen beheben Fehler, Minor-Versionen fügen abwärtskompatibel Funktionen hinzu, Major-Versionen dürfen brechen. In der Praxis halten sich die meisten Pakete daran – aber eben nicht alle, und nicht immer absichtlich.

Ein Bugfix, der ein Verhalten korrigiert, auf das sich dein Code (unwissentlich) verlassen hat, ist technisch ein Patch und praktisch ein Breaking Change. Deshalb gilt:

Sicherheitswarnungen einordnen

npm audit und die GitHub-Warnungen sind nützlich, erzeugen aber viel Lärm. Nicht jede gemeldete Schwachstelle betrifft dich. Eine Regex-DoS-Lücke in einem Paket, das nur im Build-Prozess mit deinen eigenen Dateien läuft, ist etwas völlig anderes als dieselbe Lücke in einem Paket, das Nutzereingaben auf dem Server verarbeitet.

Das heißt nicht, dass du Warnungen ignorieren sollst. Es heißt, dass du sie priorisieren musst: Was läuft in Produktion? Was verarbeitet Eingaben von außen? Das wird zuerst behoben. Den Rest nimmst du in der normalen Update-Routine mit.

Was du dagegen nicht tun solltest: blind npm audit fix --force ausführen. Der Befehl hebt Pakete notfalls über Major-Versionen hinweg an und kann dir genau die Breaking Changes einbauen, die du vermeiden wolltest.

Wenn das Projekt schon verwahrlost ist

Alles oben setzt voraus, dass du bei einem halbwegs aktuellen Stand startest. Was, wenn nicht?

Dann schalte den Bot nicht einfach ein – du bekommst sonst hundert PRs, die sich gegenseitig blockieren. Geh stattdessen schrittweise vor:

  1. Laufzeitumgebung zuerst. Node, PHP, Python auf eine unterstützte Version bringen. Viele andere Updates hängen davon ab.
  2. Das Framework als Nächstes, eine Major-Version nach der anderen, jeweils mit dem offiziellen Upgrade-Guide. Versionen zu überspringen spart selten Zeit.
  3. Dann der Rest, in Gruppen, mit einem Commit pro Gruppe.
  4. Erst danach den Bot aktivieren, damit der Stand gehalten wird.

Das ist Arbeit, und bei Kundenprojekten gehört sie ehrlich ins Angebot. Ein Update-Rückstand von mehreren Jahren ist kein „kurzes Aufräumen“, und wer das so verkauft, zahlt am Ende drauf.

Wann sich das alles nicht lohnt

Um ehrlich zu sein: Nicht jedes Projekt braucht diese Routine. Eine statische Seite, die einmal gebaut und als HTML ausgeliefert wird, hat zur Laufzeit keine Abhängigkeiten, die angreifbar wären. Ein internes Skript, das einmal im Quartal läuft, kann auch mal ein Jahr ruhen.

Sobald aber ein Server Anfragen aus dem Internet annimmt, ist regelmäßiges Updaten keine Kür mehr. Und die Routine kostet, wenn sie einmal eingerichtet ist, erstaunlich wenig: ein Blick am Montag, ein paar Klicks, gelegentlich ein Changelog.

Welche Renovate-Konfiguration bei euch funktioniert und wo Automerge schon mal danebenging, darüber tauschen wir uns im Discord der Community regelmäßig aus – gerade die Fehlschläge sind dort oft lehrreicher als die Erfolgsgeschichten.