headless-wordpress-astro-setup.html
< BACK Vintage-Schreibtisch mit Manuskriptseiten und Tonbandgerät im warmen goldenen Stundenlicht

Headless WordPress + Astro: Ein funktionierendes Setup für inhaltsreiche Websites

Ein Kunde rief mich Anfang 2023 an – ein Medienverleger mit etwa 14.000 WordPress-Posts, einem Theme, das über sechs Jahre von vier Entwicklern zusammengestückelt worden war, und einem Core Web Vitals Score, der wirklich peinlich war. Sein LCP lag auf Mobilgeräten bei 7,2 Sekunden. Sie hatten WP Rocket versucht, sie hatten ein CDN versucht, sie hatten sogar die Hälfte ihrer Plugins entfernt. Immer noch langsam. Das Problem war nicht WordPress selbst. Es war, dass jeder einzelne Seitenaufruf durch PHP, ein aufgeblähtes Theme und eine Datenbankabfragekette lief, die seit 2018 nicht mehr angefasst worden war.Core Web Vitals score that was genuinely embarrassing. Their LCP was clocking in at 7.2 seconds on mobile. They'd tried WP Rocket, they'd tried a CDN, they'd even stripped half their plugins. Still slow. The problem wasn't WordPress itself. It was that every single page render was going through PHP, a bloated theme, and a database query chain that hadn't been looked at since 2018.

Wichtigste Erkenntnis: Headless WordPress mit Astro ist der optimale Ansatz für Content-Seiten: wp-admin für Redakteure, statisch-schnelles Frontend für Besucher und WPGraphQL als Schnittstelle zwischen beiden.Headless WordPress with Astro is the content-site sweet spot: wp-admin for editors, static-fast front end for visitors, and WPGraphQL bridging the two.

Das war der Moment, in dem ich mich richtig auf eine Headless-Lösung mit Astro als Frontend festgelegt habe. Nicht weil es gerade modern ist – sondern weil für eine Website mit Tausenden von Beiträgen und umfangreichen redaktionellen Inhalten das einzige Architektur-Design war, das Sinn ergibt.Astro as the frontend. Not because it's fashionable -- because for a site pushing thousands of posts with heavy editorial content, it was the only architecture that made sense.

Hier ist genau, wie ich es aufgebaut habe. Die Kompromisse, die echte Konfiguration, die Dinge, die mir Probleme bereitet haben.

---

Warum Astro und nicht Next.js

Diese Frage bekomme ich häufig gestellt. Next.js ist die offensichtliche Antwort, wenn du bereits ein React-starkes Team hast oder wenn du komplexe clientseitige Interaktivität brauchst. Aber für inhaltsreiche Websites? Astro gewinnt, und es ist nicht besonders knapp.Next.js is the obvious answer if you've already got a React-heavy team or you need complex client-side interactivity. But for content-heavy sites? Astro wins, and it's not particularly close.

Astro versendet standardmäßig null JavaScript. Für einen Blog, eine News-Website oder ein Dokumentations-Portal – das ist die richtige Voreinstellung. Du aktivierst JavaScript dort, wo du es brauchst, anstatt dich aus einem 200-KB-React-Bundle auszuschalten, den du größtenteils gar nicht willst. Die Astro-Dokumentation zur partiellen Hydration – sie nennen es die Islands-Architektur – erklärt es besser, als ich es in einem Satz kann, aber die Kurzversion ist: Nur die interaktiven Teile bekommen JS. Der Artikel-Body, der Header, die Sidebar? Statisches HTML.zero JavaScript by default. For a blog, a news site, or a documentation portal, that's the correct default. You opt into JavaScript where you need it, rather than opting out of a 200kb React bundle you mostly don't want. The Astro docs on partial hydration -- they call it the Islands architecture -- explain it better than I can in a sentence, but the short version is: only the interactive bits get JS. The article body, the header, the sidebar? Static HTML.

Ich habe Ende 2022 eine Legal-Content-Website mit Next.js und WordPress gebaut. Schnell genug, aber der Kunde fragte ständig, warum sein Lighthouse-Score auf Mobilgeräten bei 74 lag, wenn „es jetzt schnell sein sollte". Hydration-Overhead. Mit Astro erreicht dieselbe Art von Website routinemäßig 95–98. Nicht um zu prahlen – das ist einfach das, was dir die Architektur kostenlos gibt.

Wofür Astro nicht gut geeignet ist

Es lohnt sich, ehrlich zu sein. Wenn deine Website Echtzeit-Personalisierung, einen umfangreichen Warenkorb oder etwas braucht, das wirklich von clientseitigem State über viele Komponenten hinweg abhängt, fühlt sich Astro unbeholfen an. Es ist keine React-App. Das Islands-Pattern ist mächtig, aber es ist ein anderes mentales Modell als das Bauen von SPAs. Ich habe versucht, ein Client-Dashboard in ein Astro-Projekt zu zwingen, Mitte 2023, und bin innerhalb von zwei Wochen zu Next.js zurückgekehrt. Wisse, was du baust.

---

WordPress als Headless CMS einrichten

WordPress ist ein wirklich gutes Headless-Backend. Die WP REST API ist im Core enthalten, sie ist gut dokumentiert, und dein Editorial-Team muss nichts Neues lernen. Dieser letzte Punkt ist wichtiger, als Entwickler normalerweise zugeben.WP REST API ships in core, it's well-documented, and your editorial team doesn't have to learn anything new. That last point matters more than developers usually admit.

Hier ist das Setup, das ich verwende:

  1. Installiere WordPress auf einer Subdomain -- ich verwende cms.yourdomain.com oder api.yourdomain.com. Halte es hinter Basic Auth oder beschränke zumindest den direkten öffentlichen Traffic. Das Frontend ist yourdomain.com. Zwei separate Deployments. -- I use cms.yourdomain.com or api.yourdomain.com. Keep it behind basic auth or at minimum restrict direct public traffic. The frontend is yourdomain.com. Two separate deployments.
  2. Installiere das [WPGraphQL-Plugin](https://www.wpgraphql.com/) -- ich bevorzuge GraphQL gegenüber REST für Content-Sites, weil du deine Queries zusammen mit deinen Komponenten platzieren kannst und genau die Felder abrufst, die du brauchst. Kein Over-Fetching. Die REST API funktioniert einwandfrei, aber sobald du 15+ Custom Fields pro Post Type hast, ist der GraphQL-Ansatz deutlich sauberer. -- I prefer GraphQL over REST for content sites because you can co-locate your queries with your components and fetch exactly the fields you need. No over-fetching. The REST API is fine, but once you've got 15+ custom fields per post type, the GraphQL approach is noticeably cleaner.
  3. Installiere Advanced Custom Fields (ACF) und die WPGraphQL for ACF Extension. Diese Kombination macht WordPress als Headless-Content-Modell wirklich flexibel -- du kannst strukturierte Daten pro Post Type definieren, sie über GraphQL exponieren, und Astro konsumiert sie sauber. and the WPGraphQL for ACF extension. This combo is what makes WordPress genuinely flexible as a headless content model -- you can define structured data per post type, expose it through GraphQL, and Astro consumes it cleanly.
  4. Deaktiviere Kommentare, Emojis und das Standard-XML-RPC, falls du das noch nicht getan hast. Diese fügen Overhead und Angriffsfläche hinzu, die du nicht brauchst. if you haven't already. These add overhead and attack surface you don't need.
  5. Stelle die Permalinks auf etwas Sinnvolles ein, bevor du anfängst zu bauen. Sie mitten im Projekt zu ändern, wenn deine Astro-Routes bereits gesetzt sind, ist echtes Ärger. to something sensible before you start building. Changing them mid-project when your Astro routes are already set is a genuine pain.

Eine Sache, bei der Menschen hängenbleiben: CORS. Standardmäßig erlaubt WordPress deinem Astro-Dev-Server (läuft auf localhost:4321) nicht, Requests an deine WP-Installation zu stellen. Füge das während der Entwicklung in die functions.php deines Themes oder ein kleines Utility-Plugin ein:localhost:4321) make requests to your WP install. Drop this into your theme's functions.php or a small utility plugin during development:

`` add_action('init', function() { header("Access-Control-Allow-Origin: *"); }); `` add_action('init', function() { header("Access-Control-Allow-Origin: *"); }); ``

Verschärfen Sie das auf spezifische Ursprünge in der Produktion. Offensichtlich.

---

Die Astro-Projektstruktur

Ich halte das durchdacht und konsistent über Projekte hinweg. Nach einem Dutzend oder so Headless-Builds ist das, was funktioniert:

`` src/ components/ layouts/ pages/ index.astro blog/ [slug].astro lib/ wpgraphql.ts ← alle WP-Abfragelog ik lebt hier styles/ `` src/ components/ layouts/ pages/ index.astro blog/ [slug].astro lib/ wpgraphql.ts ← all WP query logic lives here styles/ ``

Die Datei lib/wpgraphql.ts ist, wo ich jeden GraphQL-Fetch zentralisiere. Keine eingestreuten Fetch-Aufrufe verteilt über Seitendateien. Jede Abfrage ist eine benannte, exportierte async-Funktion. Das Debuggen über 14.000 Beiträge hinweg, wenn etwas um 2 Uhr morgens bricht – Sie werden sich später dafür danken.lib/wpgraphql.ts file is where I centralise every GraphQL fetch. No inline fetch calls scattered across page files. Every query is a named, exported async function. Debugging this across 14,000 posts when something breaks at 2am -- you'll thank yourself later.

Beiträge zur Build-Zeit abrufen

Astros getStaticPaths ist hier deine Hauptstütze. Für einen Blog mit Tausenden von Beiträgen:getStaticPaths is your bread and butter here. For a blog with thousands of posts:

`` export async function getStaticPaths() { const posts = await getAllPostSlugs(); // ruft WPGraphQL auf return posts.map(post => ({ params: { slug: post.slug }, })); } `` export async function getStaticPaths() { const posts = await getAllPostSlugs(); // calls WPGraphQL return posts.map(post => ({ params: { slug: post.slug }, })); } ``

getAllPostSlugs paginiert durch WPGraphQL mit After-Cursorn – Wordpress' GraphQL-Schicht gibt standardmäßig 100 Beiträge pro Anfrage zurück, also machst du für 14.000 Beiträge 140 Anfragen zur Build-Zeit. Das klingt beängstigend. In der Praxis läuft der vollständige Build auf einem anständigen Server in etwa 4–5 Minuten. Vollkommen akzeptabel für eine Website, die ein paar Mal pro Tag neu aufgebaut wird. paginates through WPGraphQL using after cursors -- WordPress's GraphQL layer returns 100 posts per request by default, so for 14,000 posts you're making 140 requests at build time. That sounds scary. In practice, on a decent server, the full build runs in about 4-5 minutes. Perfectly acceptable for a site that rebuilds a few times per day.

---

Bilder verwalten, ohne den Verstand zu verlieren

Das ist der Teil, über den niemand genug spricht. WordPress speichert Bild-URLs, die auf deine CMS-Subdomain zeigen. Wenn Astro statisch baut, leben diese Bilder immer noch auf cms.yourdomain.com – was bedeutet, dass die Browser deiner Besucher Bilder von deinem WordPress-Server abrufen und möglicherweise dein CDN umgehen.cms.yourdomain.com -- which means your visitors' browsers are fetching images from your WordPress server, potentially bypassing your CDN.

Ein paar Wege, wie ich das handhabe:

  • Cloudflare vor beiden Domains. Die einfachste Option. Leite beide yourdomain.com und cms.yourdomain.com durch Cloudflare, konfiguriere aggressives Caching auf /wp-content/uploads/*, und es läuft meistens ohne Probleme. Simplest option. Proxy both yourdomain.com and cms.yourdomain.com through Cloudflare, configure aggressive caching on /wp-content/uploads/*, and you're mostly fine.
  • Nutze ein Media-Offload-Plugin. Ich mag WP Offload Media – es verschiebt Uploads zu S3 (oder kompatiblem Speicher) und schreibt URLs automatisch um. Das ist der Ansatz, den ich bei Sites mit ernsthaftem Traffic nutze. Dein WordPress-Server serviert Bilder gar nicht mehr. I like WP Offload Media -- it moves uploads to S3 (or compatible storage) and rewrites URLs automatically. This is the approach I use for any site expecting serious traffic. Your WordPress server stops serving images entirely.
  • Astro's Image-Komponente. Bei Bildern, die du zur Build-Zeit kontrollierst (Featured Images, die via GraphQL abgerufen werden), kannst du die Remote-URL in Astro's <Image>-Komponente übergeben und es optimiert, skaliert und serviert sie aus deiner Build-Ausgabe. Funktioniert hervorragend. Funktioniert nicht für Bilder, die in Post-Body-HTML eingebettet sind – das erfordert einen anderen Durchgang. For images you control at build time (featured images pulled via GraphQL), you can pass the remote URL into Astro's <Image> component and it'll optimise, resize, and serve them from your build output. Works brilliantly. Does not work for images embedded in post body HTML -- that requires a different pass.

Seahawk hatte letztes Jahr einen Travel-Content-Client – etwa 8.000 Posts, extrem bilderlastig, durchschnittlich 12 Bilder pro Artikel. Ihr WordPress-Server wurde selbst mit dem Headless-Setup nur durch Bilderanfragen bombardiert. Der Umzug zu S3 + CloudFront reduzierte ihre Origin-Bandbreite um 94%. Wirklich transformativ für ihre Hosting-Rechnung.

---

Inkrementelle Builds und das Rebuild-Problem

Hier ist ein echtes Problem mit statischer Generierung im großen Maßstab: Dein Editor veröffentlicht eine Korrektur um 15 Uhr und muss dann 5 Minuten auf einen vollständigen Rebuild warten. Das ist in einer Newsroom nicht akzeptabel.

Ein paar Ansätze, die ich verwendet habe:

Option 1: Netlify oder Vercel mit On-Demand-ISR. Astro unterstützt serverseitiges Rendering mit Adaptern – du kannst Astro im Hybrid-Modus ausführen, bei dem die meisten Seiten statisch sind, aber spezifische Routes bei Bedarf gerendert werden. Bei einer Nachrichtenwebseite rendere ich die letzten 30 Tage von Posts oft statisch vor (hoher Traffic, braucht Geschwindigkeit) und stelle ältere Archivseiten auf serverseitiges Rendering bei Bedarf. Beste aus beiden Welten. Astro supports server-side rendering with adapters -- you can run Astro in hybrid mode where most pages are static but specific routes are rendered on-demand. For a news site, I'll often statically pre-render the last 30 days of posts (high traffic, needs speed) and set older archive pages to server-render on demand. Best of both worlds.

Option 2: Webhook-gesteuerte Partial Builds. WordPress feuert einen Webhook beim Speichern von Posts ab (einfach mit dem WP Webhooks Plugin). Dieser Webhook trifft einen Netlify- oder Vercel-Deploy-Hook. Der Build läuft, er holt nur das ab, was sich geändert hat. Es ist nicht wirklich partial – Astro baut immer noch alles neu auf – aber wenn du deinen Build schnell hältst, sind 4 Minuten machbar. WordPress fires a webhook on post save (easy with the WP Webhooks plugin). That webhook hits a Netlify or Vercel deploy hook. The build runs, it fetches only what's changed. It's not truly partial -- Astro still rebuilds everything -- but if you keep your build fast, 4 minutes is workable.

Option 3: Nutze einfach SSR für das ganze Ding. Deployiere Astro mit dem Node-Adapter auf ein VPS (ich nutze dafür Hetzner – günstig, schnell, zuverlässig). Jede Seite wird auf Anfrage gerendert, du cachst aggressiv auf der Nginx- oder Cloudflare-Ebene, und du hast sofortige Post-Updates. Das würde ich für einen anständigen Publishing-Betrieb mit über 50.000 Posts machen. Deploy Astro with the Node adapter to a VPS (I use Hetzner for this -- cheap, fast, reliable). Every page renders on request, you cache aggressively at the Nginx or Cloudflare level, and you have instant post updates. This is what I'd do for a proper publishing operation over 50,000 posts.

Ehrlich gesagt? Die meisten Webseiten brauchen nicht die Komplexität von Option 1 oder 3. Ein 4-Minuten-Rebuild, der durch einen Webhook ausgelöst wird, ist für 90% der Content-Seiten in Ordnung.

---

Performance: Was du wirklich bekommst

Bei dem Publisher-Projekt aus der Einleitung – hier ist, was nach der Astro-Migration passiert ist:

  • LCP ist bei Mobile von 7,2s auf 1,1s gefallen (getestet mit WebPageTest von einem London-Node)1.1s on mobile (tested with WebPageTest from a London node)
  • Total Blocking Time sank von ~800ms auf 0ms (standardmäßig null JavaScript, denk dran)0ms (zero JS by default, remember)
  • Der Google Search Console Core Web Vitals Report stieg von 3% „Gut" bewerteten URLs auf 91% „Gut" innerhalb von sechs Wochen nach dem Deployment91% "Good" within six weeks of deployment
  • Die Hosting-Kosten sanken, weil der WordPress-Server keine Seiten mehr auslieferte, sondern nur noch API-Responses

Das ist keine Magie. Es passiert einfach, wenn man PHP-Rendering aus dem kritischen Pfad entfernt und einem Leser nicht mehr ein 400kb Theme JavaScript Bundle zusendet.

---

Die Bits, die dir Probleme bereiten werden

Ehrlich gesagt – Sachen, die ich in echten Projekten debuggen musste:

  • Entwürfe von Beiträgen in der Vorschau. Das ist in einem Headless-Setup wirklich nervig. WordPress' native Vorschau setzt auf Frontend-Rendering. Du brauchst einen Custom Preview Endpoint in Astro, der einen WordPress Preview Nonce akzeptiert und den Entwurf via WPGraphQL fetcht. Nicht schwer, aber es dauert einen Tag, um es richtig zu machen. This is genuinely annoying in a headless setup. WordPress's native preview relies on front-end rendering. You need to build a custom preview endpoint in Astro that accepts a WordPress preview nonce and fetches the draft via WPGraphQL. Not hard, but it takes a day to do properly.
  • Redirects. Wenn die alte Website hunderte Redirects in .htaccess hatte, leben die jetzt auf dem WordPress-Server. Du musst sie entweder in Astros Config replizieren oder WordPress erreichbar lassen und bestimmte Pfade proxyen. Ich habe beides gemacht. In Astro zu replizieren ist langfristig sauberer. If the old site had hundreds of redirects in .htaccess, those live on the WordPress server now. You need to either replicate them in Astro's config, or keep WordPress accessible and proxy specific paths. I've done both. Replicating in Astro is cleaner long-term.
  • Suche. WordPress' eingebaute Suche ist in einem Headless-Setup nutzlos. Ich nutze Algolia mit dem WP Search with Algolia Plugin. Indexiere deine Beiträge in WP, frage Algolia von einer Astro Island Component ab. Funktioniert gut. WordPress's built-in search is useless in a headless setup. I use Algolia with the WP Search with Algolia plugin. Index your posts in WP, query Algolia from an Astro Island component. Works well.
  • Menüs und Navigation. WordPress-Menüs sind merkwürdig fummelig, wenn man sie über WPGraphQL verfügbar machen will. Die wpgraphql-acf-Route endet oft sauberer -- modelliere deine Navigation einfach als ACF Repeater und fertig. WordPress menus are weirdly fiddly to expose through WPGraphQL. The wpgraphql-acf route often ends up being cleaner -- just model your nav as an ACF repeater and call it done.

---

FAQ

Brauche ich WPGraphQL oder kann ich einfach die REST API verwenden?

Du kannst die REST API absolut verwenden -- sie ist in den WordPress-Kern integriert und erfordert keine zusätzlichen Plugins. Für einfache Seiten mit Standard-Post-Typen und minimalen benutzerdefinierten Feldern ist sie ausreichend. GraphQL rechtfertigt sich, wenn du komplexe Content-Modelle mit vielen benutzerdefinierten Feldern pro Typ hast. Die Möglichkeit, genau die Felder zu fetchen, die du brauchst, in einer einzigen Anfrage, ohne dich mit _embed-Parametern und verschachtelten REST-Calls herumzuschlagen, spart dir bei jeder Query Zeit. Letztendlich deine Entscheidung. Ich finde GraphQL einfach sauberer, sobald eine bestimmte Komplexitätsschwelle überschritten ist._embed parameters and nested REST calls, saves time on every query you write. Up to you. I just find GraphQL cleaner past a certain complexity threshold.

Wie handhabe ich WordPress-Authentifizierung für Inhalte nur für Mitglieder?

JWT-Authentifizierung ist der Standard-Ansatz. Installiere das JWT Authentication for WP REST API Plugin, stelle Tokens beim Login aus, übergebe sie in deinen GraphQL-Request-Headern. Auf der Astro-Seite würdest du das mit einer SSR-Route (nicht statisch) handhaben, damit die benutzerspezifischen Inhalte pro Request serverseitig geladen werden. Versuche nicht, das statisch zu machen -- das führt zu Wahnsinn.JWT Authentication for WP REST API plugin, issue tokens on login, pass them in your GraphQL request headers. On the Astro side, you'd handle this with an SSR route (not static) so the user-specific content is fetched server-side per request. Don't try to do this statically -- that way lies madness.

Ist das zu viel des Guten für einen kleinen Blog?

Ja, wahrscheinlich. Wenn du unter 500 Posts hast und einen Editor, lohnt sich der Aufwand zum Maintenainen eines Headless-Setups nicht. Nutze einfach ein gutes WordPress-Theme, optimiere deine Bilder, und mach dein Ding. Diese Architektur lohnt sich, wenn du Volumen, redaktionelle Komplexität oder Traffic-Level hast, wo Performance wirklich einen Unterschied beim Umsatz macht.

Wie sieht das Hosting-Setup in der Produktion aus?

WordPress (nur CMS) auf einem kleinen VPS oder managed WordPress Host – ich nutze Kinsta oder Cloudways. Astro Frontend auf Vercel, Netlify oder einen Hetzner VPS mit Nginx, je nach Projekt. Cloudflare vor allem. Die monatlichen Gesamtkosten für eine mittelgroße Content-Site liegen normalerweise bei £60–£120, was oft weniger ist als das, was Kunden für einen All-in-One WordPress Host zahlten, der unter der Last zusammenbrach.less than what clients were paying for an all-in-one WordPress host that was struggling under the load.

---

Die ehrliche Zusammenfassung ist diese: Headless WordPress mit Astro ist eines der besseren Dinge, die Content-Sites in einer Weile passiert sind. Nicht weil es neu ist, sondern weil das Tooling der Idee endlich aufgeholt hat. WPGraphQL ist stabil, Astros Build-System ist schnell, und die Performance-Gewinne sind real und messbar.

Bekomme die Architektur früh hin -- besonders deine Image-Strategie und deinen Rebuild-Ansatz -- und du wirst später viel weniger Zeit mit Löschen von Bränden verbringen. Das ist wirklich alles.

< BACK