Das Symfony-Ökosystem 2026: Welche Pakete sich lohnen

#symfony pakete
Sandor Farkas - Founder & Lead Developer at Wolf-Tech

Sandor Farkas

Gründer & Lead Developer

Experte für Softwareentwicklung und Legacy-Code-Optimierung

Jedes neue Symfony-Projekt beginnt mit derselben Frage: Welche Symfony-Pakete brauchen wir eigentlich wirklich? Packagist schlägt bereitwillig Hunderte vor. Das Framework selbst liefert bereits mehr als fünfzig Komponenten mit. Dazu kommen die Bundles von SymfonyCasts, Doctrine, API Platform und ein langer Schwanz an Ein-Personen-Projekten, die 2019 vielversprechend aussahen und seitdem keinen Commit mehr gesehen haben.

Wir prüfen im Rahmen unserer Code-Quality-Beratung viele Symfony-Codebasen, und ausufernde Abhängigkeiten gehören zu den konsistentesten Befunden. Meist ist kein einzelnes Paket das Problem. Niemand hat je gefragt, ob es wirklich gebraucht wird, und eine composer.json mit 90 Einträgen ist ein Wartungsvertrag, den niemand bewusst unterschrieben hat.

Dieser Beitrag ist unsere subjektive Liste für 2026. Sie geht von einer produktiven Symfony-7-Anwendung aus (7.4 ist das aktuelle LTS und das sinnvolle Ziel, wenn du gerade startest), PHP 8.3 oder neuer, und einem Team, das lieber wenig eigenen Code schreibt als viel fremden zu übernehmen.

Erst Symfonys eigene Komponenten, dann erst andere Symfony-Pakete

Die erste Regel bei der Paketauswahl in Symfony ist unspektakulär: Prüfe, ob das Framework es nicht schon selbst kann. In der Praxis finden wir immer wieder Rate-Limiter, UUID-Bibliotheken und HTTP-Clients von Drittanbietern, direkt neben den Symfony-Komponenten, die sie vor Jahren ersetzt haben.

Ein paar Komponenten, die in fast jede Anwendung gehören und immer noch unterschätzt werden:

symfony/rate-limiter deckt Login-Throttling, API-Kontingente und Missbrauchsschutz mit ein paar YAML-Zeilen und einem Storage-Backend ab, das du ohnehin schon hast (Redis, Doctrine oder den Cache-Pool). Teams ziehen sich für dieses Problem immer noch eigenständige Throttling-Bibliotheken rein. Nicht nötig.

symfony/uid liefert UUID-v7- und ULID-Generierung inklusive Doctrine-Typen. Wenn du ein neues Schema aufsetzt, lohnen sich UUID-basierte Primärschlüssel trotz des geringen Mehrverbrauchs an Speicher: Du kannst IDs vor dem Insert erzeugen, Daten über Umgebungen hinweg ohne Kollisionen zusammenführen und verhinderst, dass fortlaufende Integer-IDs Zeilenzahlen preisgeben. ramsey/uuid ist eine solide Bibliothek, aber als direkte Abhängigkeit brauchst du sie nicht mehr.

symfony/messenger übernimmt asynchrone Arbeit, Retries, Failure-Transports und Scheduling (seit 6.3 über symfony/scheduler). Erstaunlich viele Teams packen eine separate Job-Queue-Bibliothek obendrauf, weil sie die Retry-Strategie-Konfiguration von Messenger nicht kannten. Die operative Seite haben wir in Messenger im großen Maßstab beschrieben.

symfony/http-client ersetzt Guzzle für ausgehende Aufrufe in fast allen Fällen. Er unterstützt Retries, gescopte Clients pro API, Mocking in Tests und HTTP/2 von Haus aus. Guzzle taucht in composer.json noch auf, weil manche SDKs es voraussetzen, das ist in Ordnung, aber schreibe keinen neuen Code mehr dagegen.

symfony/serializer und symfony/validator sind die beiden anderen, die wir grundlos ersetzt sehen. Mehr zum Serializer weiter unten.

Symfony-Pakete, die sich in fast jeder Produktivanwendung verdient machen

Nach den Komponenten gibt es eine kurze Liste von Bundles, die wir in fast jedem Projekt installieren und nie bereut haben.

symfonycasts/reset-password-bundle

Passwort-Reset ist eines dieser Features, von denen jedes Team denkt, es könne es an einem Nachmittag schreiben, und dabei subtil etwas falsch macht: Tokens, die nie ablaufen, Tokens im Klartext gespeichert, kein Throttling bei Anfragen, User-Enumeration durch unterschiedliche Fehlermeldungen. Dieses Bundle handhabt den Token-Lebenszyklus korrekt, integriert sich mit dem Maker-Bundle und steht einem sonst nicht im Weg. Es sind etwa 30 Dateien. Installieren.

symfonycasts/verify-email-bundle

Gleicher Maintainer, gleiche Begründung. Signierte URLs für die E-Mail-Verifizierung, Ablaufzeiten, keine eigene Krypto-Implementierung im Code.

doctrine/doctrine-fixtures-bundle (nur dev)

Fixtures sind das Rückgrat realistischer Testdaten. Kombiniere das Bundle mit zenstruck/foundry, wenn du Factory-Style-Objekterzeugung in Tests willst. Foundry hat sich als De-facto-Standard für Symfony-Testfactories etabliert und passt gut zu zenstruck/browser für funktionale Tests. Beide gehören in require-dev.

nelmio/security-bundle

Security-Header (CSP, HSTS, X-Frame-Options, Referrer-Policy) sind mühsam von Hand zu konfigurieren und leicht falsch zu machen. NelmioSecurityBundle macht daraus Konfiguration. Man kann einen Listener schreiben, der dasselbe in einer Stunde erledigt, und manche Teams bevorzugen das. Wir greifen meist zum Bundle, weil CSP-Nonces und der Report-only-Modus genau die Teile sind, die man beim Selberbauen gerne überspringt.

scheb/2fa-bundle

Wenn deine Anwendung einen Admin-Bereich hat oder Kundendaten verarbeitet, ist Zwei-Faktor-Authentifizierung 2026 kein Nice-to-have mehr. Schebs Bundle unterstützt TOTP, E-Mail-Codes und Backup-Codes und fügt sich in Symfonys Security-System ein, statt es zu ersetzen. Es ist die Standardwahl, und wir hatten bisher keinen Grund, woanders zu suchen.

symfony/monolog-bundle

Immer noch der Logging-Standard. Konfiguriere einen JSON-Formatter für die Produktion, damit dein Log-Aggregator ihn parsen kann, und ergänze einen Fingers-crossed-Handler, damit Debug-Ausgaben nur bei Fehlern in einem Request erscheinen.

sentry/sentry-symfony (oder das Äquivalent deines Error-Trackers)

Error-Tracking ist eine Produktionsanforderung. Egal welchen Anbieter du nutzt, installiere das offizielle Bundle statt das SDK manuell zu verdrahten; das Bundle fängt Messenger-Fehler und Console-Command-Fehler ab, die eine manuelle Integration meist übersieht.

APIs: API Platform für CRUD-lastige Fälle, reines Symfony für ereignisgesteuerte

Die API-Schicht ist der Ort, an dem Paketentscheidungen die größten langfristigen Kosten verursachen, deshalb verdient sie einen eigenen Abschnitt.

Für Anwendungen, deren API größtenteils aus Ressourcen mit Standardoperationen besteht (Liste, Lesen, Erstellen, Aktualisieren, Löschen, Filtern, Paginieren), ist API Platform immer noch die beste uns bekannte Wahl. Du definierst die Ressource einmal und bekommst OpenAPI-Dokumentation, JSON-LD oder reines JSON, Pagination, Filterung, Validierungsintegration und Security-Ausdrücke. Der Beitrag zu API Platform geht auf das Setup und die Verteidigung gegen N+1-Probleme sowie Pagination ein.

Der Preis dafür ist konzeptioneller Natur. API Platform hat sein eigenes Vokabular (State-Provider, State-Prozessoren, Ressourcen-Metadaten) und eigene Vorstellungen davon, wie sich deine Domäne auf HTTP abbildet. Wenn deine API eine dünne Schicht über einem sauberen Doctrine-Modell ist, ist diese Abbildung nahezu kostenlos. Wenn deine API größtenteils aus Befehlen besteht ("Export starten", "Rechnung genehmigen", "Preise neu berechnen"), beginnt das Ressourcenmodell dagegen zu arbeiten, und am Ende schreibst du für alles benutzerdefinierte Operationen.

Für diese zweite Art von Anwendung reicht reines Symfony. Controller mit #[MapRequestPayload] für Input-DTOs, der Validator für Constraints, der Serializer für die Ausgabe und Messenger für alles, was asynchron laufen soll. Das sind vier Komponenten, die du ohnehin schon hast, und null neue mentale Modelle. Füge nelmio/api-doc-bundle hinzu, wenn du generierte OpenAPI-Dokumentation brauchst, oder schreibe das Schema zuerst und validiere dagegen; den Schema-first-Ansatz beschreiben wir in unserem Leitfaden zu OpenAPI-Contract-Testing.

Wovon wir abraten, ist, beide Muster in einer Anwendung parallel zu betreiben. Wähle das Muster, das zur Mehrheit deiner Endpunkte passt, und akzeptiere etwas Umständlichkeit bei der Minderheit.

Die Pakete, bei denen wir Teams zum Überdenken raten

Keines davon ist schlechte Software. Jedes hat einen echten Anwendungsfall. Das Problem ist, dass sie standardmäßig installiert werden, wenn der Standard eigentlich "noch nicht" lauten sollte.

JMS Serializer

JMS war der Serializer der Wahl, bevor Symfonys eigene Komponente ausgereift war. 2026 handhabt der Symfony Serializer verschachtelte Objekte, Gruppen, Naming-Strategien, Discriminator-Maps für Polymorphie und zirkuläre Referenzen. JMS handhabt einige Grenzfälle noch etwas besser (Exclusion-Policies, versionierte Properties), und wenn du bereits tief drinsteckst, gibt es keinen dringenden Grund zu migrieren. Aber für eine neue Anwendung bedeutet JMS zwei Serializer im Container mit unterschiedlichen Annotationskonventionen, und jeder neue Entwickler muss lernen, welcher wo verwendet wird. Bleib bei der Komponente, außer du stößt auf eine konkrete Einschränkung.

Sonata Admin und EasyAdmin

Admin-Bundles sind die umstrittenste Wahl auf dieser Liste, daher hier die Nuance. EasyAdmin passt gut zu einfachen CRUD-Screens über Doctrine-Entities mit einem kleinen Team, das sie nicht stark anpassen wird. Sonata ist mächtiger und komplexer, und seine Konfigurationsfläche ist so groß, dass die Anpassung oft länger dauert, als den Screen von Grund auf neu zu schreiben.

Das Muster, das wir immer wieder sehen: Ein Team installiert in Woche eins ein Admin-Bundle, verbringt die Wochen zwei bis sechs damit, es auf nicht-standardmäßige Workflows zu biegen (Freigabeschritte, Massenaktionen mit Nebenwirkungen, Multi-Entity-Formulare), und landet bei einem System, das außer dem ursprünglichen Autor niemand ändern kann. Ein einfaches Twig-Interface oder ein kleines HTMX-basiertes Admin-Panel ist nach dem ersten Monat meist schneller und lässt sich in einem Code-Review deutlich leichter nachvollziehen.

Wenn deine Admin-Anforderungen wirklich standardmäßig sind, ist EasyAdmin in Ordnung. Wenn du dich dabei ertappst, seinen internen Code zu lesen, um ein Formularfeld zu überschreiben, ist das das Signal aufzuhören.

FOSUserBundle und FOSRestBundle

Beide tauchen immer noch in Codebasen auf, die wir prüfen. FOSUserBundle ist faktisch eingestellt; das Maker-Bundle plus die SymfonyCasts-Bundles oben decken dasselbe mit weniger Magie ab. FOSRestBundle hat Probleme gelöst, die #[MapRequestPayload], der Serializer und API Platform mittlerweile nativ lösen. Wenn du eines von beiden in einem Projekt siehst, das nach 2022 datiert ist, behandle das als Modernisierungspunkt.

Firmeninterne "Core"-Bundles aus einem früheren Projekt

Teams schleppen ein firmeninternes Bundle von Projekt zu Projekt mit, weil es irgendwann einmal Zeit gespart hat. Drei Projekte später enthält es Abstraktionen für Probleme, die das aktuelle Projekt gar nicht hat. Frag, was es liefert, das Symfony 7 nicht schon kann, und übernimm nur die Teile, die diese Frage überstehen.

Wie man ein Paket vor der Aufnahme bewertet

Die konkrete Liste an Symfony-Paketen oben wird veralten. Die Bewertungsgewohnheit ist das, was zählt. Vor jedem composer require in einem Produktivprojekt gehen wir ein paar Fragen durch.

Gibt es eine Symfony-Komponente oder ein Flex-Recipe, das das schon abdeckt? Prüfe das Symfony-Flex-Recipes-Repository; wenn ein Paket ein Recipe hat, ist es zumindest gepflegt genug, dass jemand eines geschrieben hat.

Wann war das letzte Release, und erklärt es Unterstützung für deine Symfony- und PHP-Versionen? Ein Paket mit offenen Issues wie "Symfony 7 support?" ohne Antwort vom Maintainer ist ein künftiger Blocker für dein nächstes Upgrade. Das ist die größte Schmerzquelle in Legacy-Modernisierungsprojekten: Das Upgrade selbst ist unproblematisch, aber vier verwaiste Bundles halten dich an einer alten Framework-Version fest.

Wie viel vom Paket würdest du tatsächlich nutzen? Wenn du nur eine Hilfsklasse von vierzig brauchst, kopiere die Klasse (unter Beachtung der Lizenz) und verzichte auf die Abhängigkeit.

Wer sonst hängt davon ab? Prüfe die Dependents-Zahl auf Packagist. Ein Paket, das nur eine Handvoll Projekte nutzt, ist ein Paket, das du am Ende selbst pflegen musst.

Kannst du einem neuen Teammitglied erklären, warum es da ist? Wenn die ehrliche Antwort "das Tutorial hat es benutzt" lautet, entfern es.

Eine minimale composer.json für eine produktive Symfony-7-Anwendung

Das ist ungefähr, wovon wir ausgehen. Passe den API-Abschnitt je nach der Entscheidung oben an und tausche den Error-Tracker gegen deinen eigenen.

{
    "type": "project",
    "require": {
        "php": ">=8.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "doctrine/dbal": "^4",
        "doctrine/doctrine-bundle": "^2.13",
        "doctrine/doctrine-migrations-bundle": "^3.4",
        "doctrine/orm": "^3.3",
        "nelmio/security-bundle": "^3",
        "scheb/2fa-bundle": "^7",
        "scheb/2fa-totp": "^7",
        "sentry/sentry-symfony": "^5",
        "symfony/console": "7.4.*",
        "symfony/dotenv": "7.4.*",
        "symfony/flex": "^2",
        "symfony/framework-bundle": "7.4.*",
        "symfony/http-client": "7.4.*",
        "symfony/mailer": "7.4.*",
        "symfony/messenger": "7.4.*",
        "symfony/monolog-bundle": "^3.10",
        "symfony/rate-limiter": "7.4.*",
        "symfony/runtime": "7.4.*",
        "symfony/scheduler": "7.4.*",
        "symfony/security-bundle": "7.4.*",
        "symfony/serializer": "7.4.*",
        "symfony/twig-bundle": "7.4.*",
        "symfony/uid": "7.4.*",
        "symfony/validator": "7.4.*",
        "symfony/yaml": "7.4.*",
        "symfonycasts/reset-password-bundle": "^1.23",
        "symfonycasts/verify-email-bundle": "^1.17"
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^4",
        "phpstan/phpstan": "^2",
        "phpstan/phpstan-symfony": "^2",
        "phpunit/phpunit": "^11",
        "symfony/browser-kit": "7.4.*",
        "symfony/debug-bundle": "7.4.*",
        "symfony/maker-bundle": "^1.60",
        "symfony/phpunit-bridge": "7.4.*",
        "symfony/stopwatch": "7.4.*",
        "symfony/web-profiler-bundle": "7.4.*",
        "zenstruck/browser": "^1.9",
        "zenstruck/foundry": "^2"
    },
    "config": {
        "allow-plugins": {
            "php-http/discovery": true,
            "symfony/flex": true,
            "symfony/runtime": true
        },
        "sort-packages": true
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "7.4.*"
        }
    }
}

Ein paar Anmerkungen zu den Entscheidungen. Die Versionsconstraints sind Richtwerte; führe composer outdated nach der Installation aus und pinne auf das, was auflöst. PHPStan ab Level 6 von Tag eins ist günstiger, als es ein Jahr später bei Level 0 einzuführen und sich hochzuarbeiten. allow-contrib ist false, damit Flex nur Pakete mit Recipes aus dem Hauptrepository automatisch konfiguriert, was Überraschungen aus deinem Konfigurationsverzeichnis heraushält. Es gibt kein Admin-Bundle, kein JMS und kein Guzzle. Füge API Platform (api-platform/symfony) hinzu, falls dich der API-Abschnitt in diese Richtung gelenkt hat.

Diese Liste hat rund dreißig Produktivabhängigkeiten, die meisten davon Symfony-Komponenten, die gemeinsam upgraden. Das ist die Form, die du willst. Eine Framework-Version zum Hochziehen und eine Handvoll gut gepflegter Bundles drumherum.

Wenn die Paketfrage eigentlich eine Architekturfrage ist

Manchmal ist die Debatte darüber, welches Bundle installiert wird, ein Stellvertreter für eine Entscheidung, die das Team noch nicht getroffen hat: ob der Admin-Bereich eine Produktoberfläche oder ein internes Werkzeug ist, ob die API eine Ressourcen-API oder eine Befehls-API ist, ob das Projekt in drei Jahren noch von Leuten gepflegt wird, die beim Start nicht dabei waren. Pakete sind leicht hinzuzufügen und schwer wieder loszuwerden, deshalb lohnt es sich, diese Fragen vor dem ersten composer require zu klären.

Wenn du eine Symfony-Anwendung startest und eine zweite Meinung zur Abhängigkeitsliste willst, oder eine composer.json geerbt hast, die niemand erklären kann, machen wir diese Art von Review als Teil unserer individuellen Softwareentwicklung und Code-Audit-Arbeit. Schreib an hello@wolf-tech.io oder informier dich auf wolf-tech.io.