Astro-Entwickler in Stuttgart

Astro-Entwickler für Stuttgart: Content Collections mit Schema, Loader für Markdown und Fremddaten, typsichere Abfragen und Redaktionsabläufe. Remote und schriftlich aus Gdynia.

Astro-Entwickler

Migration von WordPress zu Astro in Stuttgart

Viele Unternehmen in Stuttgart nutzen WordPress, stoßen aber an Grenzen bei Performance, Sicherheit und Hosting-Kosten. Astro löst diese Probleme mit statischem HTML, null JavaScript und Edge-Deployment. Ich migriere bestehende WordPress-Seiten zu Astro mit vollständiger SEO-Erhaltung, URL-Mapping und 301-Weiterleitungen.

  • PageSpeed 95-100

    Statisches HTML ohne JavaScript. Schneller als jede WordPress-Lösung.

  • SEO-sichere Migration

    URL-Mapping, 301-Weiterleitungen, Google-Rankings erhalten.

  • Hosting auf Cloudflare Pages

    Globales CDN, kostenloses SSL, sofortige Deployments. Hosting-Kosten nahe null.

Ich bin Mariusz Szatkowski, arbeite seit 2006 mit WordPress und baue heute Websites mit Astro. Ich sitze in Gdynia in Polen und arbeite vollständig remote und schriftlich, als einzelner Entwickler. Diese Seite hat ein Thema: wie Sie die Inhalte einer Firmenwebsite in Astro so ordnen, dass Ihre Redaktion sie pflegen kann und Fehler auffallen, bevor die Seite online geht. Das Werkzeug dafür heißt Content Collections.

Haus von Hans Scharoun in der Weißenhofsiedlung in Stuttgart

Foto: Andreas Praefcke, CC BY 3.0, Wikimedia Commons.

#Warum Stuttgarter Firmen viele gleichartige Inhalte pflegen

Die Stadt Stuttgart beschreibt auf ihrer Seite zu den Top-Branchen (Stand 11.02.2026) das Ingenieurwesen als europäisches Kompetenzzentrum für Maschinenbau und Elektrotechnik, mit Werkzeugmaschinen, Industrielasern, Hochleistungselektronik, Medizintechnik und Umwelttechnik. Zur Medienbranche nennt sie Fachbücher, Fachzeitschriften und wissenschaftliche Publikationen: 16 Prozent der deutschen Verlage haben ihren Sitz in Baden-Württemberg, gut ein Viertel davon in Stuttgart.

Für eine Website ist das ein Strukturthema. Ein Hersteller führt Produkte mit Varianten, Datenblättern und Zertifikaten. Ein Verlag führt Titel, Autorinnen und Reihen. Beide haben dutzende bis tausende Einträge, die dieselben Felder brauchen. Genau dafür sind Content Collections gebaut: Die Astro-Dokumentation beschreibt eine Collection als eine Menge zusammengehöriger, gleich aufgebauter Daten, ob als Ordner voller Markdown-Dateien, als eine JSON-Datei oder als Abruf aus einem CMS oder einer API. Jeder Eintrag heißt dort entry.

#Wann Content Collections sich lohnen und wann nicht

Die Dokumentation nennt klare Fälle. Eine Collection lohnt sich, wenn Sie viele Dateien mit gleicher Struktur haben, wenn Inhalte bereits in einem CMS liegen und Sie die Hilfsfunktionen statt eigener fetch()-Aufrufe nutzen wollen, oder wenn Sie zehntausende Einträge beim Build laden müssen. Sie lohnt sich nicht bei nur einer Handvoll verschiedener Seiten: Dann empfiehlt die Dokumentation einzelne Seitenkomponenten wie src/pages/about.astro. Auch PDFs, die Astro nicht verarbeitet, gehören nach public/ und nicht in eine Collection.

Ich prüfe das vor dem Start an Ihrer Inhaltsliste:

InhaltAnzahl, BeispielCollection?
Produkte oder Titel40 Einträge mit gleichen FeldernJa
Stellenanzeigenwechselnd, 3 bis 15 EinträgeJa
Meldungen und Fachbeiträgelaufend, mit Datum und AutorJa
Startseite, Über uns, Impressumje genau eine SeiteNein, eigene Seitenkomponente
Datenblätter als PDFDateienNein, nach public/

#Eine Collection definieren: Loader und Schema

Alle Collections, die beim Build geladen werden, stehen laut Dokumentation in src/content.config.ts. Jede besteht aus einem Loader (Pflicht) und einem Schema (optional, aber ausdrücklich empfohlen). Das Schema schreiben Sie mit Zod, das Astro über astro/zod bereitstellt. Ein Beispiel für einen Maschinenbauer, mit einer Datei pro Produkt und einer gemeinsamen Datenblatt-Liste:

// src/content.config.ts
import { defineCollection, reference } from "astro:content";
import { glob, file } from "astro/loaders";
import { z } from "astro/zod";

const downloads = defineCollection({
  loader: file("src/data/downloads.json"),
  schema: z.object({
    id: z.string(),
    titel: z.string(),
    datei: z.string(),
    sprache: z.enum(["de", "en"]),
  }),
});

const produkte = defineCollection({
  loader: glob({ base: "./src/content/produkte", pattern: "**/*.{md,mdx}" }),
  schema: z.object({
    titel: z.string(),
    beschreibung: z.string().max(160),
    veroeffentlicht: z.coerce.date(),
    entwurf: z.boolean().default(false),
    datenblatt: reference("downloads").optional(),
  }),
});

export const collections = { downloads, produkte };

Drei Punkte darin sind Entscheidungen, keine Syntax. Erstens sprache: z.enum(["de", "en"]): Ein Tippfehler wie "dt" ist kein gültiger Wert und fällt auf. Zweitens reference("downloads"): Das Datenblatt eines Produkts muss in der Download-Liste existieren, ein toter Verweis ist keine Seite mit kaputtem Link, sondern ein Fehler im Editor. Drittens entwurf mit Standardwert: Neue Einträge sind gültig, bleiben aber unsichtbar, bis jemand sie freigibt.

#Loader: Markdown, JSON und Daten aus fremden Quellen

Astro liefert laut Loader-Referenz zwei Loader mit, beide seit Astro 5.0.0.

  • glob() liest Verzeichnisse mit Markdown, MDX, Markdoc, JSON, YAML oder TOML. Die ID eines Eintrags entsteht aus dem Dateinamen, ein slug im Frontmatter überschreibt sie. Bei sehr großen Collections lässt sich mit retainBody: false (seit Astro 5.17.0) der Rohtext aus dem Datenspeicher heraushalten, und mit deferRender: true (seit Astro 7.1.0) wird Markdown erst beim Rendern der Seite verarbeitet, um den Arbeitsspeicher beim Build zu schonen.
  • file() liest eine einzelne Datei mit vielen Einträgen. Jeder Eintrag braucht eine eigene id, das Format wird an der Dateiendung erkannt. Für andere Formate wie CSV gibt es einen parser.

Für Daten aus einem CMS, einer Datenbank oder einer Schnittstelle gibt es keinen mitgelieferten Loader. Die Dokumentation zeigt zwei Wege. Der kurze ist ein Loader als Funktion, die ein Array von Einträgen mit id zurückgibt:

const stellen = defineCollection({
  loader: async () => {
    const antwort = await fetch("https://api.example.com/stellen");
    if (!antwort.ok) throw new Error(`Stellen-API: ${antwort.status}`);
    const daten = await antwort.json();
    return daten.map((s: { kennung: string }) => ({ id: s.kennung, ...s }));
  },
  schema: z.object({
    id: z.string(),
    titel: z.string(),
    standort: z.string(),
  }),
});

Der ausführliche Weg ist ein Loader-Objekt mit name, einer load()-Methode und optional einem eigenen Schema. load() bekommt unter anderem store, parseData und einen Logger und leert und füllt den Datenspeicher selbst. Ich nehme ihn, wenn die Quelle seitenweise liefert, Felder umbenannt werden müssen oder ein Fehler lesbar protokolliert werden soll. Für verbreitete Systeme gibt es Loader der Community, die die Astro-Integrationsliste führt. Ob einer zu Ihrem System passt und gepflegt wird, prüfe ich vor dem Einsatz.

Eine Regel aus der Dokumentation, die ich oft erkläre: Definiert die Collection in content.config.ts ein eigenes Schema, gilt dieses statt des Schemas im Loader. So können Sie das Schema eines Fremd-Loaders erweitern oder umformen.

#Typsichere Abfragen

Die Abfrage läuft über getCollection() für alle Einträge und getEntry() für einen. Das Schema erzeugt daraus TypeScript-Typen, der Editor ergänzt Feldnamen und meldet falsche. Zwei Details, an denen Projekte stolpern:

---
import { getCollection, getEntry } from "astro:content";

const produkte = (
  await getCollection("produkte", ({ data }) => !data.entwurf)
).sort((a, b) => b.data.veroeffentlicht.valueOf() - a.data.veroeffentlicht.valueOf());

const erstes = produkte[0];
const datenblatt = erstes?.data.datenblatt
  ? await getEntry(erstes.data.datenblatt)
  : undefined;
---

Die Sortierung steht im eigenen Code, weil die Dokumentation ausdrücklich sagt, dass die Reihenfolge der Einträge nicht festgelegt und plattformabhängig ist. Und der Filter hält Entwürfe aus der Produktion heraus; wer sie lokal sehen will, prüft zusätzlich import.meta.env.PROD, wie es die Dokumentation zeigt.

Seiten entstehen aus Collections nicht von selbst. Für statische Ausgabe rufe ich getCollection() in getStaticPaths() auf und erzeuge pro Eintrag eine Route aus seiner id; der Inhalt kommt über render().

#Build-Zeit oder Live: welche Collection wofür

Die Dokumentation unterscheidet zwei Arten und empfiehlt, Build-Time-Collections zu nehmen, wo es geht.

Build-Time-CollectionLive-Collection
Konfigurationsrc/content.config.ts, defineCollection()src/live.config.ts, defineLiveCollection()
AbrufgetCollection(), getEntry()getLiveCollection(), getLiveEntry()
Wann geladenbeim Build, im Datenspeicher abgelegtbei jeder Anfrage
MDX und Bildoptimierungjanein
Adapter nötigneinja
Typisch fürProdukte, Meldungen, DokumentationLagerbestand, Entwurfsvorschau im CMS

Live-Collections gibt es seit Astro 6.0.0. Beide Arten dürfen im selben Projekt stehen: Produktbeschreibungen als Build-Time-Collection, der Lagerbestand als Live-Collection. Ich schlage Live nur vor, wenn jemand wirklich frische Daten braucht, denn jede Anfrage hängt dann an der Quelle.

#Wie Ihre Redaktion damit arbeitet

Content Collections prüfen und liefern Inhalte, sie sind keine Eingabemaske. Wer Inhalte ohne Entwickler pflegen will, braucht eine der folgenden Varianten. Die Astro-Dokumentation zu CMS listet Guides unter anderem für CloudCannon (dort als Git-basiertes CMS beschrieben), Decap CMS, Keystatic, Contentful, Sanity, Storyblok, Strapi, Directus, Payload CMS und WordPress.

VarianteWo liegen die InhalteWie arbeitet die Redaktion
Dateien im RepositoryMarkdown und JSON neben dem CodeÄnderungen über Pull Requests, geeignet für ein kleines technisches Team
Git-basiertes CMSweiterhin Dateien, mit Eingabemaske davorFormular statt Markdown, das Schema steht im CMS und in content.config.ts
Headless-CMS per Loaderbeim AnbieterRedaktion im CMS, Astro holt beim Build
WordPress als Quellein Ihrer WordPress-InstallationRedaktion bleibt, Astro übernimmt das Frontend

Mein Vorgehen: Ich frage zuerst, wer heute Inhalte pflegt und wie oft. Eine Redaktion, die täglich in WordPress arbeitet, soll dort bleiben, dann liest ein Loader die Inhalte aus. Ein kleines Team, das Produkte zweimal im Jahr ändert, kommt mit Dateien aus. Die Entscheidung dazwischen liegt bei Ihnen, ich schreibe die Vor- und Nachteile pro Variante schriftlich auf. Mehr zu WordPress als Redaktionssystem hinter Astro steht auf der Seite Headless-CMS-Entwickler und, für Stuttgart, unter WordPress-Entwickler in Stuttgart.

Bei einer Vorschau für Redakteure sind Live-Collections der richtige Baustein: Die Dokumentation nennt ausdrücklich den Fall, dass Redakteure Entwürfe sofort sehen sollen.

#Datenschutz, sobald ein externes System dazukommt

Ein CMS oder eine Schnittstelle ist ein Dienst, der Daten verarbeitet: mindestens die Konten Ihrer Redakteure, oft auch Formulareingänge oder Bewerbungen. Der Landesbeauftragte für den Datenschutz und die Informationsfreiheit Baden-Württemberg (LfDI BW) beschreibt in seiner Praxishilfe zur Auftragsverarbeitung folgende Punkte, die für ein solches Setup zählen:

  • Die Auftragsverarbeitung braucht einen Vertrag mit Gegenstand, Dauer, Art und Zweck der Verarbeitung, Art der Daten und Kategorien der Betroffenen (Art. 28 Abs. 3 DSGVO).
  • Der Vertrag muss schriftlich oder in einem elektronischen Format vorliegen (Art. 28 Abs. 9 DSGVO). Laut LfDI genügt dafür nicht jede bestätigende E-Mail; ein gesetztes Häkchen kann genügen, wenn dokumentiert ist, welcher Inhalt bestätigt wurde.
  • Setzt der Anbieter Unterauftragnehmer ein, braucht er vorab Ihre schriftliche Genehmigung, auch elektronisch, und Sie haben ein Einspruchsrecht.
  • Sitzt der Anbieter außerhalb der EU, gelten zusätzlich die Anforderungen aus Kapitel V der DSGVO.

Der LfDI BW stellt auf seiner Seite mit Praxishilfen ein Muster für den Auftragsverarbeitungsvertrag nach Art. 28 Abs. 3 DSGVO bereit. Den Text der DSGVO finden Sie auf EUR-Lex. Ich bin Entwickler, kein Anwalt: Die rechtliche Bewertung bleibt bei Ihrer Rechtsberatung. Mein Teil ist die technische Inventur. Vor dem Start liste ich jeden Dienst auf, der in Ihrem Projekt Daten erhält (CMS, Formulare, Hosting, Newsletter), und wo er seine Server hat. Bei Dateien im Repository und Build-Time-Collections entfällt ein Teil dieser Liste, weil Besucher Ihrer Seite nie mit einem CMS sprechen: Die Seite ist fertiges HTML.

#So läuft ein Projekt mit mir

Alles läuft in Textform: Mails und Dokumente, keine Termine, keine Anrufe.

  1. Briefing. Sie schicken mir URL, Ziel, Termin, den aktuellen Stack und die Liste Ihrer Inhaltstypen. Ich lese Ihre Unterlagen und frage in Textform nach.
  2. Inhaltsmodell. Ich schreibe pro Inhaltstyp die Felder auf, mit Pflichtfeldern, erlaubten Werten und Verweisen. Sie bestätigen das Modell, bevor ich Code schreibe.
  3. Umfang und Annahmen. Ich halte fest, was dazugehört, was nicht, und was ich voraussetze. Layout und Grafik liefern Sie, zum Beispiel als markierte Tabelle mit den Elementen je Ansicht, ich setze sie um.
  4. Aufbau auf einer Testumgebung. Sie sehen den Stand jederzeit auf einer Vorschau-Adresse.
  5. Abnahme. Sie prüfen den Stand Punkt für Punkt gegen den vereinbarten Umfang. Wünsche außerhalb davon erfasse ich als neues Angebot.
  6. Start und Wartung. Zum Start schalte ich die Domain um, hinterlege Weiterleitungen alter URLs und prüfe in den Tagen danach die Crawl-Fehler. Updates der Abhängigkeiten pflege ich auf Wunsch, dazu siehe Wartung und Support in Stuttgart.

Kommt Ihre Seite von Next.js oder WordPress, lesen Sie vorher die Seite Migration von Next.js zu Astro in Stuttgart. Ist Ihr Projekt eher eine Anwendung als eine Website, hilft Next.js-Entwicklung in Stuttgart bei der Einordnung. Braucht die Seite ein eigenes Backend, finden Sie das unter PHP-Entwickler in Stuttgart.

#Checkliste vor dem Start (auch ohne mich nutzbar)

FrageWarum sie zählt
Welche Inhaltstypen gibt es, und wie viele Einträge je Typ?Entscheidet, ob Collection oder Einzelseite
Welche Felder sind Pflicht, welche Werte sind erlaubt?Wird zum Schema und fängt Fehler vor dem Start ab
Wer pflegt welchen Inhalt, wie oft?Bestimmt Dateien, Git-basiertes CMS, Headless-CMS oder WordPress
Wie frisch müssen Inhalte sein?Build-Time oder Live-Collection
Welche externen Dienste erhalten personenbezogene Daten?Eingabe für Auftragsverarbeitungsverträge und Datenschutzerklärung
Gibt es Entwürfe, die niemand vorab sehen darf?Entwurfsfeld, Filter und Vorschau-Weg
Wer liefert Layout und Texte, bis wann?Ohne Layout kein Start, ohne Texte kein Abschluss

#Häufige Fragen

#Brauche ich Content Collections für eine Website mit zehn Seiten?

Meist nicht. Die Astro-Dokumentation rät bei nur wenigen unterschiedlichen Seiten zu einzelnen Seitenkomponenten, etwa src/pages/about.astro. Collections lohnen sich, wenn viele Einträge dieselbe Struktur haben: Produkte, Stellen, Meldungen, Ansprechpartner.

#Kann Astro Inhalte aus meinem bestehenden CMS lesen?

Ja, über einen Loader oder das SDK des Anbieters. Die Astro-Dokumentation führt Guides unter anderem für WordPress, Contentful, Sanity, Storyblok, Strapi, Directus und Payload CMS. Welcher Weg passt, hängt davon ab, wie Ihre Redaktion heute arbeitet und wie aktuell die Inhalte sein müssen.

#Was passiert, wenn ein Redakteur ein Pflichtfeld vergisst?

Passt ein Eintrag nicht zum Schema, meldet Astro einen Fehler. Mein Deployment läuft nur nach einem erfolgreichen Build, eine unvollständige Seite geht so nicht online. Bei einem Headless-CMS sperrt zusätzlich das CMS selbst leere Pflichtfelder, wenn ich sie dort als erforderlich anlege.

#Brauche ich einen Auftragsverarbeitungsvertrag mit dem CMS-Anbieter?

Sobald der Anbieter personenbezogene Daten in Ihrem Auftrag verarbeitet, zum Beispiel Redakteurskonten oder Formulareingänge, verlangt Art. 28 Abs. 3 DSGVO einen Vertrag. Der LfDI Baden-Württemberg stellt ein Muster bereit. Die rechtliche Prüfung gehört zu Ihrer Rechtsberatung, ich liefere die technische Liste der beteiligten Dienste.

#Wie aktuell sind die Inhalte bei einer Build-Time-Collection?

So aktuell wie der letzte Build. Live-Collections lesen bei jeder Anfrage frisch, brauchen dafür einen Adapter und unterstützen laut Dokumentation weder MDX noch Bildoptimierung. Für Produktseiten und Meldungen genügt meist die Build-Variante.

#Was muss ich Ihnen vor dem Projektstart schicken?

Die URL der aktuellen Website, das Ziel, einen Termin falls es einen gibt, den aktuellen Stack und die Liste der Inhaltstypen mit je ein bis zwei Beispielen. Das Layout kommt von Ihnen, ich setze es technisch um.

#Schreiben Sie mir

Schicken Sie mir über das Kontaktformular die URL Ihrer Website, Ihr Ziel, Ihren Termin, den aktuellen Stack und eine Liste der Inhalte, die Sie pflegen. Ich lese Ihre Angaben, frage in Textform nach und schicke Ihnen eine erste Einschätzung zu Inhaltsmodell, Umfang und Annahmen. Mein erster schriftlicher Aufschlag zu Inhaltsmodell und Umfang ist unentgeltlich. Wenn Astro oder Content Collections nicht die richtige Wahl sind, sage ich Ihnen das und nenne die Alternative.

Brauchen Sie die Leistung: Astro-Entwickler in Stuttgart?

Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.

Projekt beschreiben

Weitere WordPress-Dienste und Wissensbasis entdecken