Zruck zum Blog, du Zniachtl
Juni 2026·4 Min. zum LesnVo da KI gmocht

A praktischer Leitfodn zu Semantic Versioning

#devops#npm#best-practices

^2.4.1 in ana package.json schaut präzise aus, aber des Caret ändert seine Bedeutung, je nachdem ob da Maintainer auf da ondern Seitn die Regeln, auf denen's aufbaut, tatsächlich befolgt hot. Semantic Versioning (Semver) is a Versprechen, codiert in drei Zohln - und es funktioniert nur ois Versprechen, wenn sowohl Herausgeber ois a Konsument genau vastehn, wozu's sich verpflichtet.

De drei Zohln

A Semver-Version is MAJOR.MINOR.PATCH, und jede Position hot a konkrete Bedeutung:

  • MAJOR - erhöht bei Breaking Changes. Olles, wos bestehenden korrekten Code zum Aufhörn bringen kunnt: a entfernte Funktion, a umbenannter Parameter, a geänderter Rückgabetyp, a neichs Pflicht-Config-Feld.
  • MINOR - erhöht für neiche, abwärtskompatible Funktionalität. Neiche optionale Parameter, neiche exportierte Funktionen, neiche Config-Optionen mit vernünftigen Defaults.
  • PATCH - erhöht für abwärtskompatible Bugfixes. Koa neiche Funktionalität, koa Verhaltensänderung außer "des, wos kaputt woar, funktioniert jetzt wia dokumentiert".

1.4.2 → 1.5.0 heißt "wos Neis, nix soit kaputtgehn". 1.4.2 → 2.0.0 heißt "lies s'Changelog vor'm Upgraden". Diese Unterscheidung is der gesamte Wert von Semver - sie lasst Tooling und Menschen Upgrade-Entscheidungen treffen, ohne jeden Commit zum lesn.

Wos als "breaking" zählt, is strenger, ois es si anfühlt

Da Instinkt is, Major-Bumps für dramatische Rewrites zum reserviern, aber Semvers Definition bezieht si auf jede inkompatible API-Änderung, wia klan sie a sei mag:

// v1.2.0
function formatPrice(amountCents) {
  return `$${(amountCents / 100).toFixed(2)}`;
}

// v1.3.0 — adding an optional param is fine, existing callers are unaffected
function formatPrice(amountCents, currency = 'USD') {
  return `${currency} ${(amountCents / 100).toFixed(2)}`;
}

// v2.0.0 — changing the parameter's meaning breaks every existing caller
function formatPrice(amountDollars, currency = 'USD') {
  return `${currency} ${amountDollars.toFixed(2)}`;
}

Diese letzte Änderung is a Einzeiler-Diff und schaut klan aus, aber jeder Aufrufer, der Cent übergibt, kriagt jetzt still a falsches Ergebnis statt an Fehler - wos sie schlimmer mocht ois a lauten Breaking Change, ned besser. Es is a Major-Bump, egal wia klan die Code-Änderung ausschaut.

Eine öffentlich exportierte Funktion entfernen, a Funktion von synchron auf Promise-Rückgabe umstellen, akzeptierte Eingabetypen einengen, Fehlermeldungen ändern, auf die Aufrufer per Pattern-Matching reagieren - das sand olles Breaking Changes, a wenn koans davon si wia "a großer Rewrite" anfühlt.

Versionsbereiche: Wos ^ und ~ tatsächlich versprechen

npm install schreibt Bereichsoperatoren in die package.json, und die ergeben nur im Licht dessen Sinn, wos Semver garantiert:

{
  "dependencies": {
    "lodash": "^4.17.21",
    "express": "~4.18.2",
    "left-pad": "1.3.0"
  }
}
  • ^4.17.21 (Caret) - akzeptiert jede Version, de die linkeste Nicht-Null-Zoi ned ändert. Also 4.17.21 bis (ausschließlich) 5.0.0 - jedes Minor- oder Patch-Update, koa Majors. Des is npms Standard und die richtige Wahl für die meisten Abhängigkeiten: Du kriagst Bugfixes und neiche Features automatisch, Breaking Changes verlangen a explizite Aktion.
  • ~4.18.2 (Tilde) - akzeptiert nur Patch-Updates: 4.18.2 bis (ausschließlich) 4.19.0. Konservativer - neiche Features wählst du manuell.
  • 1.3.0 (exakt) - ka Updates ohne Bearbeitung der package.json. Passt, wenn a Abhängigkeit a Geschichte hot, Semver zu brechn, oda wennst voll reproduzierbare Builds unabhängig von da package-lock.json brauchst.

Die "linkeste Nicht-Null"-Regel vom Caret hot a scharfe Kante bei Pre-1.0-Paketen: ^0.4.2 akzeptiert nur Patch-Updates (0.4.x), koane Minor-Updates, weil vor 1.0.0 die zwoate Zoi ois Breaking-Change-Position gilt. Semver dokumentiert 0.x.y ausdrücklich ois "olles kann sich jederzeit ändern" - und genau deswegn zählt's, a Bibliothek auf a stabile 1.0.0 zu bringen.

Eigenes Paket veröffentlichn: Das Versprechen richtig geben

Wennst a Paket pflegst, liegt die Disziplin bei dir, ned bei deine Nutzer:

  1. Entscheid den Bump, bevor du den Release entscheidst. Schau dir den Diff seit dem letzten Release o und kategorisier ihn: Irgendein Breaking Change irgendwo → Major. Koane Breaking Changes aber neiche Features → Minor. Sonst → Patch. Wähl ned zuerst die Versionsnummer und rationalisier dann die Kategorie zurecht.
  2. Nimm npm version statt Handarbeit. Es aktualisiert die package.json, erstöt an Git-Tag und erzwingt gültige Semver-Strings.
npm version patch   # 1.4.2 -> 1.4.3
npm version minor    # 1.4.2 -> 1.5.0
npm version major    # 1.4.2 -> 2.0.0
  1. Schreib pro Release an Changelog-Eintrag, ned nur a Commit-Log. "Wos is kaputt, wos is neich, wos is gfixt" - drei Sätze reichen, aber des is der Unterschied zwischen am Konsumenten, der selbstbewusst upgradet, und am Konsumenten, der dein Paket aus Angst für immer festnagelt.
  2. Deprecate, bevor du entfernst. Mark die oide API ois deprecated (in Docs, in JSDoc, mit ana Laufzeit-Warnung) für mindestens a Minor-Release, bevor du sie in ana Major entfernst - des gibt Konsumenten a Migrationsfenster statt ana Überraschung.

Pre-Release und Build-Metadaten

Semver definiert a Suffixe für Versionen vor da allgemeinen Verfügbarkeit:

2.0.0-alpha.1
2.0.0-beta.3
2.0.0-rc.1
2.0.0

De sortieren vor der schlichten Version, der sie vorausgehn (2.0.0-rc.1 < 2.0.0), und Paketmanager installiern sie ned über an normalen Bereich, außer ma verlangt's explizit - npm install mypackage@next oda a exakte Pre-Release-Version. So lieferst a Major-Version in Arbeit zum frühen Testn aus, ohne dass jeder ^1.x.x-Konsument versehentlich unfertige, brechende Orbeit einezieht.

Fazit

Semver is a Vertrag, ka Formalität: MAJOR verspricht "lies des vor'm Upgraden", MINOR verspricht "sicher zum automatisch nehmen, do is wos Neis", PATCH verspricht "nix hot si gändert außer dass a Bug gfixt wurde". Die Versionsbereichs-Operatoren in da package.json schützen dich nur, wenn die Pakete, von denen du abhängst, den Vertrag tatsächlich einhoitn - und deine eigenen veröffentlichten Pakete schützen deine Konsumenten nur, wenn du des Gleiche tust.

NeicherMemory Leaks in Node.js debuggnElterBig-O-Notation, erklärt mit echtem Code