Versionsangaben in der composer.json: Syntax, Bedeutung und Best Practices
Was bedeuten ^, ~, *, Bereiche, dev-Versionen und Stability-Flags in der composer.json? Dieser Leitfaden erklärt die Syntax von Composer-Versionsangaben verständlich, praxisnah und mit passenden Codebeispielen.
Die Versionsangaben in der composer.json entscheiden darüber, welche Paketversionen Composer installieren oder aktualisieren darf.
Besonders wichtig sind Operatoren wie ^ und ~, aber auch Wildcards, Versionsbereiche und Stability-Flags.
In den meisten produktiven PHP-Projekten ist ^ die sinnvollste Standardwahl, weil Sicherheits- und Bugfix-Updates möglich bleiben, ohne direkt in die nächste Major-Version zu springen.
Warum Versionsangaben in Composer so wichtig sind
Wer regelmäßig mit PHP arbeitet, kommt an Composer nicht vorbei. Spätestens beim Blick in die composer.json taucht dann die Frage auf:
Was genau bedeutet eigentlich ^11.0, ~2.8 oder 6.4.*?
Genau diese Angaben steuern, wie flexibel dein Projekt mit Abhängigkeiten umgeht. Sind sie zu eng, bleiben wichtige Updates aus. Sind sie zu weit gefasst, kann es passieren, dass beim nächsten Update plötzlich inkompatible Änderungen einziehen.
Deshalb lohnt es sich, die Syntax von Composer-Versionsangaben sauber zu verstehen. Nicht nur theoretisch, sondern mit Blick auf echte Projekte, Wartbarkeit und sichere Updates im Alltag.
So sehen Versionsangaben in der composer.json aus
Abhängigkeiten stehen in Composer in der Regel im Bereich require oder require-dev.
Rechts neben dem Paketnamen steht die Versionsregel.
{
"require": {
"laravel/framework": "^11.0",
"guzzlehttp/guzzle": "~7.8",
"symfony/console": "6.4.*"
}
}
Composer sucht dann eine reale Paketversion, die zu dieser Regel passt. Welche Version am Ende tatsächlich installiert wird,
landet anschließend in der composer.lock.
Exakte Versionen
Die einfachste Form ist eine feste Versionsnummer.
{
"require": {
"monolog/monolog": "3.6.0"
}
}
Damit wird genau diese Version akzeptiert, sonst nichts. Das kann in Ausnahmefällen sinnvoll sein, ist für normale Anwendungen aber oft zu starr. Selbst kleine Bugfixes oder Security-Updates werden dadurch blockiert, solange du die Angabe nicht manuell änderst.
Was bedeutet ^ in der composer.json?
Der Caret-Operator ^ ist die gebräuchlichste Form für Composer Version Constraints.
Er erlaubt kompatible Updates innerhalb derselben Major-Version.
{
"require": {
"laravel/framework": "^11.0"
}
}
Praktisch heißt das:
^11.0erlaubt Versionen ab11.0.0, aber kleiner als12.0.0^2.3erlaubt Versionen ab2.3.0, aber kleiner als3.0.0^0.3erlaubt Versionen ab0.3.0, aber kleiner als0.4.0
Der letzte Punkt ist wichtig: Bei Versionen kleiner 1.0 ist Composer vorsichtiger,
weil dort schon kleinere Sprünge oft nicht mehr als stabil kompatibel gelten.
Für die meisten produktiven Projekte ist ^ die beste Standardlösung.
Sie hält dein Projekt updatefähig, ohne Major-Upgrades ungeprüft hereinzulassen.
Was bedeutet ~ in Composer?
Die Tilde ~ wirkt ähnlich, ist aber meist etwas enger gefasst.
Sie eignet sich dann, wenn du Updates zulassen willst, aber den Rahmen etwas strikter setzen möchtest.
{
"require": {
"guzzlehttp/guzzle": "~7.8"
}
}
Beispiele dazu:
~7.8erlaubt Versionen ab7.8.0bis kleiner8.0.0~7.8.2erlaubt Versionen ab7.8.2bis kleiner7.9.0
Der Unterschied zu ^ fällt vor allem dann auf, wenn du sehr genau steuern willst,
wie weit Minor- oder Patch-Updates gehen dürfen.
Wildcards mit *
Composer unterstützt auch Wildcards. Damit lassen sich ganze Versionsmuster freigeben.
{
"require": {
"symfony/console": "6.4.*"
}
}
Das bedeutet zum Beispiel:
6.4.*erlaubt alle Versionen der Reihe6.4.x6.*erlaubt alle Versionen innerhalb der 6er-Hauptversion
Solche Angaben funktionieren, wirken in vielen Teams aber etwas unschärfer als ^6.4 oder ~6.4.
Deshalb greifen viele Projekte lieber zu den expliziteren Operatoren.
Versionsbereiche und Vergleichsoperatoren
Wenn du es ganz präzise brauchst, kannst du mit Vergleichsoperatoren arbeiten.
{
"require": {
"doctrine/dbal": ">=3.7 <4.0"
}
}
Übliche Operatoren sind:
>größer als>=größer oder gleich<kleiner als<=kleiner oder gleich!=ungleich
Das ist flexibel, aber auch fehleranfälliger, wenn Regeln im Team später schnell verstanden werden sollen.
Für typische Anwendungen ist ^ oft die lesbarere Wahl.
Mehrere erlaubte Versionszweige
Composer kann auch mehrere zulässige Bereiche mit || kombinieren.
Das sieht man vor allem bei Bibliotheken, die mehrere größere Framework-Versionen unterstützen.
{
"require": {
"vendor/paket": "^2.0 || ^3.0"
}
}
In diesem Fall darf Composer entweder eine passende 2er- oder 3er-Version installieren.
dev-Versionen und Branches
Nicht jede Abhängigkeit muss auf einem offiziellen Release-Tag basieren. Composer kann auch direkt einen Branch einbinden,
zum Beispiel dev-main.
{
"require": {
"vendor/paket": "dev-main"
}
}
Das ist praktisch in der Entwicklung oder bei internen Paketen, für produktive Anwendungen aber mit Vorsicht zu genießen. Ein Branch kann sich jederzeit ändern, ohne dass eine saubere Release-Grenze existiert.
Stability-Flags in Composer
Composer kennt verschiedene Stabilitätsstufen: dev, alpha, beta, RC und stable.
Mit einem Stability-Flag kannst du Ausnahmen gezielt erlauben.
{
"require": {
"vendor/paket": "^2.0@beta"
}
}
Damit dürfen innerhalb dieses Bereichs auch Beta-Versionen verwendet werden. Das ist nützlich, wenn du ein neues Release testen willst, ohne dein ganzes Projekt auf instabile Pakete umzustellen.
Häufig tauchen außerdem diese beiden Einstellungen auf:
{
"minimum-stability": "stable",
"prefer-stable": true
}
Diese Kombination ist in vielen Projekten sinnvoll, weil sie grundsätzlich stabile Releases bevorzugt, einzelne Ausnahmen aber trotzdem zulässt.
Was man in der Praxis beachten sollte
Genau hier passieren in echten Projekten die meisten Fehler. Nicht wegen der Syntax selbst, sondern weil ihre Wirkung falsch eingeschätzt wird.
- Verwende
^, wenn du normale kompatible Updates zulassen willst. - Setze exakte Versionen nur dann ein, wenn du wirklich hart pinnen musst.
- Nutze
dev-mainnicht leichtfertig in produktiven Anwendungen. - Halte Versionsregeln in der
composer.jsonund die tatsächlichen Stände in dercomposer.lockauseinander. - Prüfe nach Änderungen immer, welche Updates Composer tatsächlich durchführen würde.
- Zu offene Regeln machen Wartung nicht einfacher, sondern oft unberechenbarer.
Hilfreiche Composer-Befehle
Wer Versionskonflikte oder Update-Spielräume besser verstehen will, sollte diese Befehle kennen:
composer validate
composer show
composer outdated
composer update vendor/paket
Gerade composer outdated ist im Alltag nützlich, weil du schnell siehst, ob ein Paket veraltet ist
oder ob deine aktuelle Versionsangabe ein Update verhindert.
Best Practice:
Wenn du keine besondere Ausnahme brauchst, starte mit ^.
Das ist in den meisten Composer-Projekten die sauberste Balance aus Stabilität, Wartbarkeit und Updatefähigkeit.
Fazit
Die Versionsangaben in der composer.json sind kein Nebendetail, sondern ein zentraler Teil jeder sauberen PHP-Wartung.
Wer versteht, wie ^, ~, Wildcards, Bereiche und Stability-Flags funktionieren,
vermeidet viele typische Composer-Probleme schon im Vorfeld.
Am Ende geht es nicht darum, möglichst komplizierte Regeln zu bauen, sondern die richtige Balance zu finden: genug Freiraum für sichere Updates, aber genug Kontrolle, damit das Projekt berechenbar bleibt.