TYPO3 schneller machen: erst messen, dann optimieren
Wo bei einer TYPO3-Seite die Zeit bleibt, welche Stellschrauben messbar etwas bringen – und welche Messfehler zu falschen Schlüssen führen.
Kurz: „TYPO3 ist langsam“ ist fast nie die ganze Wahrheit. Eine Seite kommt entweder aus dem Seitencache – dann dauert sie meist deutlich unter 200 Millisekunden –, oder TYPO3 rendert sie neu, oder es baut nach dem Leeren der Caches alles von vorn auf. Jeder dieser Zustände hat eigene Ursachen und eigene Lösungen. Der größte Hebel ist fast immer, dass Besucher den Seitencache treffen; danach lohnen sich Menüs, Datenbank und Webserver. Wer misst, bevor er optimiert, spart sich die Hälfte der Arbeit.
Drei Zustände, drei Ursachen
Die Werte stammen aus einem unserer Projekte, einem mehrsprachigen Unternehmensauftritt mit rund 160 Menüpunkten, gemessen im September 2026 auf der Staging-Umgebung:
| Zustand | Wann er eintritt | Dauer | Was die Zeit kostet |
|---|---|---|---|
| Seite kommt aus dem Seitencache | Normalfall für Besucher | 50–150 ms | fast nichts, zwei Datenbankabfragen |
| Seite ist nicht im Cache | nach einer Änderung, beim ersten Aufruf einer URL | ~0,75 s | PHP: Menüs und Rootline, rund 300 Abfragen |
| Erster Aufruf nach dem Leeren der Caches | nach jedem Deploy, nach „Cache leeren“ im Backend | ~1,3 s (vorher 1,9 s) | Schreiblast: rund 500 Abfragen, davon gut 200 Schreibvorgänge |
Wer diese Zustände vermischt, zieht falsche Schlüsse: Ein schnelleres Menü hilft im zweiten Zustand, im dritten kaum. Stellen Sie deshalb vor jeder Messung fest, in welchem Zustand Sie messen.
So messen Sie belastbar
- Immer dasselbe Protokoll. Zum Beispiel: OPcache aufwärmen, dann achtmal die Caches leeren und jedes Mal den ersten Aufruf derselben URL messen, am Ende den Median nehmen. Einzelwerte schwanken zu stark.
- Eine Änderung pro Messung. Nur dann wissen Sie, welche Änderung welche Wirkung hatte.
- Nicht hochrechnen. Die Ersparnis einer Datenbankeinstellung haben wir zunächst aus der Schreiblatenz des Speichers geschätzt: 172 Synchronisierungen zu je 5 bis 6 Millisekunden, also rund 0,9 Sekunden. Gemessen waren es 0,22 Sekunden – die Datenbank bündelt Schreibvorgänge, die einfache Rechnung lag um den Faktor vier daneben.
- Auch außerhalb von TYPO3 suchen. Hängt nur jede vierte oder fünfte Anfrage, liegt es selten am CMS. In unserem Fall zeigte das Access-Log des Webservers, dass die langsamen Anfragen erst rund vier Sekunden nach dem Absenden überhaupt begannen: Sie warteten auf einen freien Worker (mehr dazu unter „Webserver“).
Die Stellschrauben mit der größten Wirkung
1. Nach dem Deploy den Cache vorwärmen
Viele Deploys leeren am Ende den Seitencache. Danach zahlt der erste Besucher jeder URL den vollen Aufbau – in unserer Messung 1,04 Sekunden statt 0,18. Die Extension EXT:warming ruft nach dem Deploy alle URLs aus der XML-Sitemap auf; in unserem Projekt 217 URLs in vier Sprachen in rund 20 Sekunden. Am besten läuft das in einem eigenen Pipeline-Schritt, damit der Deploy nicht darauf warten muss.
Aber nacheinander, nicht parallel. Parallele Anfragen können sich bei der Bildverarbeitung in die
Quere kommen: TYPO3 verarbeitet ein Bild in eine temporäre Datei, deren Name für alle Anfragen gleich
ist, und überspringt die Verarbeitung, wenn die Datei schon existiert. Kommt eine zweite Anfrage,
während die erste noch schreibt, übernimmt sie die halbfertige Datei. Bei uns blieb danach ein leeres
Bild mit 0 Byte gespeichert, das TYPO3 nicht neu erzeugte. Mit einer Anfrage zur Zeit (concurrency
auf 1 in den Crawler-Optionen) tritt das nicht auf.
2. Den Seitencache in Redis – und nur ihn
Liegt der Seitencache in Redis statt in der Datenbank, übersteht er auch einen Neustart des TYPO3-Servers; die Seite startet dann nicht kalt. Zwei Lektionen aus dem Betrieb:
- Nur der große Seitencache gehört dorthin. Die kleinen Caches
hashundrootline, von denen das Rendering unmittelbar abhängt, bleiben in der Datenbank. Geht ein Eintrag im Seitencache verloren, ist das nur ein Cache-Miss; ein unvollständiger Rootline-Cache endet dagegen in Fehlern. - Redis darf ausfallen. Mit der Extension b13/graceful-cache läuft die Seite bei einem
Redis-Ausfall ungecacht weiter, statt mit Fehler 503 zu antworten. Startet Redis danach leer neu,
passen die in der Datenbank gespeicherten Cache-Informationen nicht mehr dazu – dann müssen alle
Caches einmal geleert werden. Wir erkennen den Neustart automatisch an der Laufkennung von Redis
(
run_id), die sich bei jedem Start ändert.
3. Menüs und Rootline: das Teuerste an einer ungecachten Seite
Ein Menü mit mehreren Ebenen fragt die Datenbank Menüpunkt für Menüpunkt ab, dazu Übersetzungen und den aktiven Pfad. Bei drei Ebenen und rund 160 Menüpunkten kamen so rund 300 Abfragen zusammen – der größte Teil eines ungecachten Aufrufs. Wegoptimieren lässt sich das kaum, aber es darf nicht mehrfach passieren:
- Das Menü einmal erzeugen. Haupt-, Mega- und Mobilmenü aus denselben Daten rendern – ein
MenuProcessor, dessen Ergebnis alle drei Templates nutzen –, statt jedes Menü einzeln zu bauen. - Die Rootline nicht doppelt holen. In einer Breadcrumb-Navigation wurde die Rootline zweimal ermittelt, einmal für die Bedingung und einmal für die Schleife, und für jede Ebene zusätzlich der Seitendatensatz geladen. Dabei enthält jeder Eintrag der Rootline bereits den vollständigen Datensatz der Seite. Einmal holen, in eine Variable legen, fertig.
- Verdächtige prüfen, bevor Sie umbauen. Nicht alles, was teuer aussieht, ist es. Eine Bildabfrage im Menü lief in unserem Fall nur auf einer einzigen Seite. Zählen Sie die Abfragen, statt zu raten.
4. Datenbank: Treiber und Schreiblast
pdo_mysql statt mysqli. Mit mysqli geht jede Abfrage in zwei Schritten zum Server:
vorbereiten, dann ausführen. pdo_mysql setzt die Parameter standardmäßig schon auf der PHP-Seite ein
und braucht nur einen Schritt. Gemessen: 0,26 statt 0,59 Millisekunden pro Abfrage. Bei 300 bis 500
Abfragen einer ungecachten Seite sind das rund 100 Millisekunden; beim ersten Aufruf nach dem Leeren
der Caches sparte der Wechsel 361 Millisekunden. Die Einstellung steht in config/system/settings.php
unter DB → Connections → Default → driver. Je weiter die Datenbank vom Webserver entfernt ist,
desto mehr bringt sie.
Schreiblast nach dem Leeren der Caches. Beim ersten Aufruf baut TYPO3 den Rootline-Cache neu auf,
in der Datenbank mit einem Löschen und einem Einfügen pro Eintrag. Für eine einzige Seite waren das
204 Anweisungen und 1,2 MB Transaktionslog. In der Voreinstellung schreibt MariaDB bei jedem Commit
sofort auf die Platte; mit innodb_flush_log_at_trx_commit = 2 nur noch etwa einmal pro Sekunde. Das
brachte in unserer Messung 218 Millisekunden. Der Preis: Stürzt der ganze Server ab – nicht nur die
Datenbank –, können Transaktionen der letzten Sekunde verloren gehen. Für einen CMS-Server ist das oft
vertretbar, aber eine bewusste Entscheidung.
5. Webserver: Worker nicht blockieren
Mit Apache im Prefork-Modus belegt jede Verbindung einen ganzen Worker-Prozess, solange sie offen ist – auch in der Leerlaufzeit nach der Antwort, die Keep-Alive offen hält. Hinter einem Load Balancer oder Reverse Proxy kommen wenige, lange offene Verbindungen an. Bei der Voreinstellung von fünf Sekunden Keep-Alive und nur vier Workern warteten bei uns Anfragen rund vier Sekunden, obwohl TYPO3 in 0,25 Sekunden antwortete.
Abhilfe: KeepAliveTimeout auf eine Sekunde verkürzen und die Zahl der Worker an den Speicher
anpassen – Worker mal PHP-memory_limit plus OPcache und Bildverarbeitung müssen in den verfügbaren
Speicher passen.
6. Frontend: was Besucher sehen
- Das wichtigste Bild zuerst. Liegen in einem Slider alle Bilder von Anfang an im HTML, lädt der
Browser sie mit gleicher Priorität; das sichtbare teilt sich die Bandbreite mit den unsichtbaren.
fetchpriority="high"am ersten undfetchpriority="low"an allen anderen Bildern ordnet das –highallein reicht nicht. In TYPO3 13 lässt sich das Attribut direkt anf:imagesetzen.loading="lazy"ist in Slidern, die einzelne Slides klonen, keine gute Idee: Das geklonte Bild kann beim ersten Durchlauf leer bleiben. - Platz reservieren gegen Layout Shift. Bilder ohne
widthundheighthaben beim Laden zunächst keine Höhe und schieben den Inhalt darunter nach unten. Der ViewHelperf:imagegibt die Maße automatisch aus, ein eigenesimg-Tag mitf:uri.imagenicht. Dasselbe gilt für einen fest positionierten Header, dessen Höhe erst ein Skript nach dem Laden korrigiert: Die tatsächliche Höhe gehört ins CSS, dann hat die Korrektur nichts mehr zu tun. - WebP ausliefern, etwa mit
fileExtension="webp"anf:image– aber nicht für SVG, die dabei gerastert würden, und nicht für animierte GIFs, deren Animation je nach Bildwerkzeug verloren geht. - Schriften mit
font-display: swapeinbinden, damit Text sofort in einer Ersatzschrift erscheint.
Vorsicht beim Browser-Cache für HTML
TYPO3 kann Cache-Header senden, damit Browser ganze Seiten zwischenspeichern (config.sendCacheHeaders).
Für Besucher ist das schnell, für Redakteure verwirrend: Sie sehen nach einer Änderung weiter den alten
Stand. In einem Projekt haben wir das deshalb bewusst abgeschaltet. Der Seitencache auf dem Server
bringt den größten Teil der Wirkung ohne dieses Problem.
In dieser Reihenfolge vorgehen
- Messprotokoll festlegen und bestimmen, in welchem Zustand die Seite langsam ist.
- Cache nach dem Deploy vorwärmen – die größte Wirkung für Besucher.
- Wartezeit am Webserver ausschließen (Access-Log, Keep-Alive, Zahl der Worker).
- Ungecachte Seite: Menüs, Rootline, eigene Datenverarbeitung.
- Datenbank: Treiber und Schreiblast.
- Frontend: wichtigstes Bild, Layout Shift, Bildformate, Schriften.
Hilfe bei einer langsamen Seite
Viele dieser Stellschrauben liegen nicht in TYPO3, sondern im Betrieb darunter – auch die PHP-Version gehört dazu. Wie wir TYPO3-Seiten betreiben, steht bei TYPO3 Hosting. Ist Ihre Seite konkret zu langsam, hilft unser TYPO3 Support – oder schreiben Sie uns über das Formular unten.
Stand: 24.9.2026 · Quellen: TYPO3 Caching Framework, EXT:warming, b13/graceful-cache, MariaDB: InnoDB-Systemvariablen, web.dev: Fetch Priority, web.dev: Cumulative Layout Shift
Erstgespräch vereinbaren
Gerne beraten wir Sie in einem kostenlosen Erstgespräch.
Was passiert nach dem Absenden?
- Wir melden uns in der Regel innerhalb eines Werktages.
- Wir klären kurz Ihr Anliegen und schlagen die nächsten Schritte vor.
- Auf Wunsch vereinbaren wir ein kostenloses Erstgespräch (ca. 60 Min.).
Danke!
Wir haben Ihre Nachricht erhalten und melden uns umgehend.