Astro Islands Architecture mit Claude Code 2026

Astro ist das schnellste Framework für content-heavy Websites — Islands Architecture liefert genau so viel JavaScript wie nötig, nicht mehr. Claude Code kennt jede Direktive, jeden Adapter und jede Astro-DB-API auswendig.

Wer 2026 eine performante Website baut, kommt an Astro kaum vorbei. Das Framework hat sich von einem Static-Site-Generator zu einer vollständigen Web-Plattform entwickelt: Server-Side Rendering, Astro DB, View Transitions und die berühmte Islands Architecture sind heute Production-ready. Claude Code kennt den gesamten Astro-5-Stack und generiert korrekte .astro-Komponenten, typsichere Content Collections und optimierte Deployment-Konfigurationen — ohne dass du jede API-Referenz auswendig lernen musst.

Was du lernst: Astro Grundkonzept & Zero-JS-Ansatz, Islands Architecture mit allen client:-Direktiven, Content Collections mit Zod-Validierung, SSR-Adapter, Astro DB mit Drizzle ORM und Performance-Optimierung mit View Transitions.

1. Astro Grundkonzept — Zero-JS by Default

Astro verfolgt einen radikal anderen Ansatz als Next.js oder Remix: Standardmäßig wird kein JavaScript an den Browser ausgeliefert. Jede .astro-Datei besteht aus zwei Teilen: dem Frontmatter (zwischen ----Trennlinien) und dem Template. Das Frontmatter läuft ausschließlich auf dem Server zur Build-Zeit — nie im Browser.

ASTRO Grundstruktur einer .astro-Komponente

Claude Code generiert vollständige Astro-Komponenten mit korrektem Frontmatter-Pattern:

--- // Frontmatter — läuft NUR auf dem Server/Build import Layout from '../layouts/Layout.astro'; import Hero from '../components/Hero.astro'; import { getCollection } from 'astro:content'; // Daten werden zur Build-Zeit abgerufen const posts = await getCollection('blog'); const latestPosts = posts.slice(0, 3); // Props-Interface (TypeScript nativ unterstützt) interface Props { title?: string; } const { title = 'Startseite' } = Astro.props; --- <!-- Template — rendert zu statischem HTML --> <Layout title={title}> <Hero /> <section class="latest-posts"> <h2>Neueste Artikel</h2> <ul> {latestPosts.map((post) => ( <li> <a href={`/blog/${post.slug}`}>{post.data.title}</a> <time>{post.data.pubDate.toLocaleDateString('de-DE')}</time> </li> ))} </ul> </section> </Layout>

LAYOUT Layout-Komponente mit Slot

Layouts nutzen <slot /> als Platzhalter für Seiteninhalte — Claude Code erstellt automatisch wiederverwendbare Layouts:

--- interface Props { title: string; description?: string; } const { title, description = 'Meine Astro Website' } = Astro.props; --- <!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>{title}</title> <meta name="description" content={description} /> </head> <body> <header> <nav> <a href="/">Home</a> <a href="/blog">Blog</a> </nav> </header> <main> <slot /> <!-- Seiteninhalt wird hier eingefügt --> </main> <footer> <p>© 2026 Meine Website</p> </footer> </body> </html> <!-- Scoped Styles — gelten nur für diese Komponente --> <style> main { max-width: 1200px; margin: 0 auto; padding: 0 1rem; } </style>
Claude Code Vorteil: Claude Code versteht den Unterschied zwischen Frontmatter (Server) und Template (HTML-Output) intuitiv. Anfragen wie "erstelle eine Astro-Seite mit Blog-Listing" generieren sofort korrekten, typsicheren Code ohne manuelle Korrekturen.

2. Islands Architecture — Selektive Interaktivität

Das Herzstück von Astro ist die Islands Architecture: Interaktive UI-Komponenten (React, Vue, Svelte, Solid) werden als "Inseln" in ansonsten statisches HTML eingebettet. Jede Insel lädt ihr JavaScript nur dann, wenn es wirklich gebraucht wird — gesteuert durch client:-Direktiven.

ISLAND client:load — Sofort hydratisieren

Für Komponenten, die sofort beim Seitenaufruf interaktiv sein müssen (z.B. Navigation, Login-Buttons):

--- import Navbar from '../components/Navbar.jsx'; import SearchBar from '../components/SearchBar.tsx'; import LazyChart from '../components/Chart.vue'; import Comments from '../components/Comments.svelte'; --- <!-- client:load: JavaScript sofort laden und hydratisieren --> <Navbar client:load /> <!-- client:idle: Laden wenn Browser idle (requestIdleCallback) --> <!-- Ideal für nicht-kritische Interaktivität --> <SearchBar client:idle /> <!-- client:visible: Laden wenn Element im Viewport (IntersectionObserver) --> <!-- Perfekt für below-the-fold Inhalte --> <LazyChart client:visible /> <!-- client:visible mit threshold: 0.5 = 50% sichtbar --> <Comments client:visible={{rootMargin: "200px"}} /> <!-- client:only: NUR im Browser rendern (kein SSR) --> <!-- Für Komponenten die window/document benötigen --> import Map from '../components/LeafletMap.jsx'; <Map client:only="react" center={[52.52, 13.4]} zoom={12} /> <!-- client:media: Nur laden wenn Media Query matched --> import MobileMenu from '../components/MobileMenu.tsx'; <MobileMenu client:media="(max-width: 768px)" />

ISLAND React-Komponente als Insel

Framework-Komponenten funktionieren wie gewohnt — Astro übernimmt das Hydration-Management:

// src/components/Counter.tsx — React-Komponente import { useState } from 'react'; interface CounterProps { initialCount?: number; label: string; } export default function Counter({ initialCount = 0, label }: CounterProps) { const [count, setCount] = useState(initialCount); return ( <div className="counter-island"> <p>{label}: <strong>{count}</strong></p> <button onClick={() => setCount(c => c - 1)}>−</button> <button onClick={() => setCount(c => c + 1)}>+</button> </div> ); } --- import Counter from '../components/Counter.tsx'; --- <!-- Props werden sicher an die Insel übergeben --> <Counter client:visible initialCount={5} label="Klicks heute" />
Direktiven-Wahl: Falsche Direktiven kosten Performance. client:load für alles zu verwenden erhöht den JavaScript-Bundle unnötig. Claude Code wählt automatisch die optimale Direktive basierend auf dem Verwendungszweck der Komponente.

3. Content Collections — Typsicheres Content Management

Content Collections sind Astros eingebautes CMS-System. Markdown-, MDX- und JSON-Dateien werden automatisch mit Zod-Schemas validiert — du bekommst TypeScript-Typen für jeden Frontmatter-Wert, vollständige Autovervollständigung und Build-Zeit-Fehler bei ungültigen Daten.

CONTENT Collection Schema definieren

Das Schema wird in src/content/config.ts definiert und bei jedem Build überprüft:

// src/content/config.ts import { defineCollection, z } from 'astro:content'; // Blog-Collection mit vollständiger Zod-Validierung const blogCollection = defineCollection({ type: 'content', // 'content' für MD/MDX, 'data' für JSON/YAML schema: z.object({ title: z.string().min(5).max(100), description: z.string().min(10), pubDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), author: z.string().default('Redaktion'), image: z.object({ url: z.string(), alt: z.string(), }).optional(), tags: z.array(z.string()).default([]), draft: z.boolean().default(false), readingTime: z.number().positive().optional(), category: z.enum(['tutorial', 'news', 'case-study', 'opinion']), }), }); // Authors als Data-Collection (JSON/YAML) const authorsCollection = defineCollection({ type: 'data', schema: z.object({ name: z.string(), bio: z.string(), avatar: z.string().url(), social: z.object({ twitter: z.string().optional(), github: z.string().optional(), }), }), }); export const collections = { blog: blogCollection, authors: authorsCollection, };

CONTENT getCollection() und getEntry()

Collections abfragen, filtern und sortieren — vollständig typsicher:

--- import { getCollection, getEntry } from 'astro:content'; import Layout from '../../layouts/Layout.astro'; // Alle publizierten Posts abrufen (draft:false filtern) const allPosts = await getCollection('blog', ({ data }) => { return data.draft === false; }); // Nach Datum sortieren (neueste zuerst) const sortedPosts = allPosts.sort( (a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime() ); // Nach Tags filtern const astroPosts = allPosts.filter( post => post.data.tags.includes('astro') ); // Einzelnen Author abrufen const author = await getEntry('authors', 'max-mustermann'); --- <Layout title="Blog"> <section> {sortedPosts.map(post => ( <article> <h2><a href={`/blog/${post.slug}`}>{post.data.title}</a></h2> <p>{post.data.description}</p> <div class="meta"> <span>{post.data.author}</span> <time>{post.data.pubDate.toLocaleDateString('de-DE')}</time> {post.data.tags.map(tag => <span class="tag">{tag}</span>)} </div> </article> ))} </section> </Layout>

CONTENT Dynamische Routen mit getStaticPaths()

Individuelle Blog-Post-Seiten werden automatisch für alle Collection-Einträge generiert:

--- import { getCollection, getEntry } from 'astro:content'; // Pflicht für statische Builds: alle Pfade vorausberechnen export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.slug }, props: { post }, })); } const { post } = Astro.props; const { Content } = await post.render(); // Markdown → HTML // Verwandten Author abrufen (type-safe!) const author = await getEntry('authors', post.data.author); --- import Layout from '../../layouts/Layout.astro'; <Layout title={post.data.title} description={post.data.description} > <article> <h1>{post.data.title}</h1> <div class="author"> <img src={author?.data.avatar} alt={author?.data.name} /> <span>{author?.data.name}</span> </div> <Content /> <!-- Markdown wird hier gerendert --> </article> </Layout>
Schema-Validierung bei Build: Fehlt ein Pflichtfeld oder hat ein Wert den falschen Typ, bricht der Build mit einem klaren Fehler ab. Claude Code fügt beim Erstellen von Markdown-Dateien automatisch alle Pflichtfelder aus dem Schema ein.

4. Server-Side Rendering — Astro als vollständiger Backend

Ab Astro 4 ist SSR stabil und Production-ready. Mit dem Umstieg auf output: 'server' wird Astro zur vollständigen Full-Stack-Lösung: dynamische Seiten, API Routes, Middleware, Authentifizierung und Datenbankzugriff — alles in einem Framework.

SSR astro.config.mjs — Output und Adapter

Der Adapter bestimmt die Deployment-Plattform. Claude Code generiert die passende Konfiguration:

// astro.config.mjs import { defineConfig } from 'astro/config'; import node from '@astrojs/node'; // VPS / Docker import vercel from '@astrojs/vercel'; // Vercel Serverless import cloudflare from '@astrojs/cloudflare'; // Cloudflare Pages/Workers import react from '@astrojs/react'; import tailwind from '@astrojs/tailwind'; export default defineConfig({ output: 'server', // 'static' | 'hybrid' | 'server' adapter: node({ mode: 'standalone' }), // Node.js Adapter integrations: [ react(), // React Islands aktivieren tailwind(), // Tailwind CSS ], // Hybrid-Mode: Seiten können individuell prerendern // output: 'hybrid' → Standard: SSR, opt-in: static // Vercel Adapter Alternative: // adapter: vercel({ imageService: true, webAnalytics: { enabled: true } }), vite: { envPrefix: 'PUBLIC_', // Nur PUBLIC_* Vars im Client }, });

SSR API Routes — REST Endpoints in Astro

API Routes werden als .ts-Dateien in src/pages/api/ erstellt:

// src/pages/api/newsletter.ts — POST Endpoint import type { APIRoute } from 'astro'; export const POST: APIRoute = async ({ request, locals }) => { const data = await request.json(); // Input-Validierung if (!data.email || !data.email.includes('@')) { return new Response( JSON.stringify({ error: 'Ungültige E-Mail-Adresse' }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } // Datenbankzugriff via Locals (Middleware setzt runtime-Context) const { db } = locals.runtime.env; try { await db.prepare('INSERT INTO subscribers (email) VALUES (?)') .bind(data.email) .run(); return new Response( JSON.stringify({ success: true, message: 'Erfolgreich angemeldet!' }), { status: 200, headers: { 'Content-Type': 'application/json' } } ); } catch (error) { return new Response( JSON.stringify({ error: 'Datenbankfehler' }), { status: 500, headers: { 'Content-Type': 'application/json' } } ); } }; // GET Endpoint für Subscriber-Count export const GET: APIRoute = async ({ request }) => { const count = 42; // aus DB lesen return new Response(JSON.stringify({ count })); };

SSR Middleware — Auth und Context

Astro Middleware (src/middleware.ts) läuft vor jeder Request-Verarbeitung:

// src/middleware.ts import { defineMiddleware } from 'astro:middleware'; export const onRequest = defineMiddleware(async (context, next) => { const { request, locals, cookies, redirect } = context; // Session aus Cookie lesen const sessionToken = cookies.get('session')?.value; if (sessionToken) { // User in locals speichern → in Seiten via Astro.locals verfügbar locals.user = await validateSession(sessionToken); } // Protected Routes absichern const isProtected = request.url.includes('/dashboard'); if (isProtected && !locals.user) { return redirect('/login?redirect=' + request.url); } return next(); });

5. Astro DB + Drizzle — Eingebautes ORM

Astro DB ist eine in Astro integrierte Datenbankschicht basierend auf Drizzle ORM und libSQL (SQLite-kompatibel). Lokal läuft die Datenbank als SQLite-Datei, in Production verbindet sich Astro DB automatisch mit Turso oder einem kompatiblen libSQL-Server.

DB Datenbankschema definieren

Das Schema wird in db/config.ts mit der Astro DB API definiert:

// db/config.ts — Astro DB Schema import { defineDb, defineTable, column, NOW } from 'astro:db'; // Tabellen definieren const Author = defineTable({ columns: { id: column.number({ primaryKey: true }), name: column.text(), email: column.text({ unique: true }), bio: column.text({ optional: true }), createdAt: column.date({ default: NOW }), }, }); const Post = defineTable({ columns: { id: column.number({ primaryKey: true }), slug: column.text({ unique: true }), title: column.text(), body: column.text(), authorId: column.number({ references: () => Author.columns.id }), published: column.boolean({ default: false }), views: column.number({ default: 0 }), publishedAt: column.date({ optional: true }), }, }); const Comment = defineTable({ columns: { id: column.number({ primaryKey: true }), postId: column.number({ references: () => Post.columns.id }), content: column.text(), authorEmail: column.text(), approved: column.boolean({ default: false }), createdAt: column.date({ default: NOW }), }, }); export default defineDb({ tables: { Author, Post, Comment }, });

DB Seed-Daten und Queries

Astro DB bietet typsichere Drizzle-Queries direkt in .astro-Dateien:

// db/seed.ts — Entwicklungs-Daten import { db, Author, Post } from 'astro:db'; export default async function seed() { // Autor anlegen await db.insert(Author).values([ { name: 'Max Mustermann', email: 'max@example.com', bio: 'Astro-Enthusiast' }, { name: 'Anna Schmidt', email: 'anna@example.com' }, ]); // Posts anlegen await db.insert(Post).values([ { slug: 'astro-islands-erklaert', title: 'Astro Islands erklärt', body: 'Islands Architecture in der Praxis...', authorId: 1, published: true, }, ]); } --- import { db, Post, Author, eq, desc, and } from 'astro:db'; // Einfache Query: alle publizierten Posts const posts = await db.select().from(Post) .where(eq(Post.published, true)) .orderBy(desc(Post.publishedAt)); // JOIN: Posts mit Author-Namen const postsWithAuthors = await db .select({ title: Post.title, slug: Post.slug, authorName: Author.name, views: Post.views, }) .from(Post) .innerJoin(Author, eq(Post.authorId, Author.id)) .where( and( eq(Post.published, true), eq(Post.authorId, 1) ) ); // Views erhöhen (in API Route) await db.update(Post) .set({ views: sql`${Post.views} + 1` }) .where(eq(Post.slug, slug));
Lokale vs. Production DB: In der Entwicklung nutzt Astro DB SQLite (keine Konfiguration nötig). In Production muss ASTRO_DB_REMOTE_URL und ASTRO_DB_APP_TOKEN gesetzt sein. Claude Code generiert automatisch die passenden Environment-Variablen-Dokumentation.

6. Performance — Core Web Vitals und View Transitions

Astro-Websites erreichen in unabhängigen Benchmarks konsistent bessere Core Web Vitals als Next.js oder Remix — hauptsächlich weil standardmäßig kein JavaScript ausgeliefert wird. Mit View Transitions kommen SPA-ähnliche Navigation-Animationen ohne den JavaScript-Overhead einer echten SPA.

PERF View Transitions API — SPA-Navigation

Astro 3+ integriert die native View Transitions API für fließende Seitenübergänge:

--- import { ViewTransitions } from 'astro:transitions'; --- <html lang="de"> <head> <title>{title}</title> <ViewTransitions /> <!-- Aktiviert SPA-Navigation sitewide --> </head> <body> <slot /> </body> </html> --- <!-- Blog-Listing: Hero-Bild mit Namen versehen --> <img src={post.data.image} alt={post.data.title} transition:name={`hero-${post.slug}`} /> <h2 transition:name={`title-${post.slug}`}> {post.data.title} </h2> <!-- Blog-Detail: Dasselbe Element → flüssige Morphing-Animation --> <img src={post.data.image} alt={post.data.title} transition:name={`hero-${post.slug}`} <!-- Gleicher Name! --> /> <h1 transition:name={`title-${post.slug}`}> {post.data.title} </h1> <!-- Transition-Animationen anpassen --> <aside transition:name="sidebar" transition:animate="slide"> <Sidebar /> </aside> <!-- Element persistent halten (kein Re-Mount bei Navigation) --> <audio transition:persist src="/podcast.mp3" controls />

PERF Performance-Vergleich 2026

Realwelt-Benchmarks für content-heavy Websites (Blog mit 50 Seiten, 10 interaktiven Komponenten):

// Lighthouse Scores — Realwelt-Vergleich 2026 // (content-heavy Blog, ähnliche Funktionalität) Framework | LCP | TBT | CLS | JS Bundle | Lighthouse -----------------+--------+--------+--------+-----------+----------- Astro 5 (static) | 0.8s | 0ms | 0.001 | ~5 KB | 99-100 Astro 5 (SSR) | 1.1s | 10ms | 0.001 | ~5 KB | 96-99 Next.js 15 | 2.1s | 180ms | 0.05 | ~89 KB | 78-85 Remix 2 | 1.8s | 120ms | 0.03 | ~72 KB | 82-88 Gatsby 5 | 1.5s | 90ms | 0.02 | ~65 KB | 85-90 // Astro-Vorteil: Islands senden NUR das JS der interaktiven Komponenten // Beispiel: 3 React-Islands auf einer Seite → ~23 KB (nicht 89 KB) // Optimal: Bild-Optimierung mit Astro Image import { Image, Picture } from 'astro:assets'; --- import { Image } from 'astro:assets'; import heroImage from '../assets/hero.jpg'; --- <!-- Automatisch: WebP-Konvertierung, srcset, lazy loading, korrekte Dimensionen --> <Image src={heroImage} alt="Hero Bild" width={1200} height={630} loading="eager" <!-- LCP-Element: eager statt lazy! --> format="webp" quality={80} />

PERF Prefetching und Asset-Optimierung

Astro 5 bietet eingebautes Prefetching für noch schnellere Navigation:

// astro.config.mjs — Prefetch-Konfiguration export default defineConfig({ prefetch: { prefetchAll: true, // Alle Links im Viewport prefetchen defaultStrategy: 'viewport', // Alternativen: 'hover', 'tap', 'load' }, image: { // Remote-Bilder erlauben (für externe Quellen) domains: ['images.unsplash.com', 'cdn.example.com'], // Oder Wildcard: remotePatterns: [{ protocol: 'https' }], }, compressHTML: true, // HTML-Ausgabe komprimieren vite: { build: { rollupOptions: { output: { // Manuelle Chunks für besseres Caching manualChunks: { react: ['react', 'react-dom'], }, }, }, }, }, }); --- <!-- data-astro-prefetch: Link explizit prefetchen --> <a href="/wichtige-seite" data-astro-prefetch="hover"> Wichtige Seite </a> <!-- Prefetch deaktivieren für externe Links --> <a href="https://external.com" data-astro-prefetch="false"> Externer Link </a>
Claude Code und Astro 2026: Claude Code kennt den kompletten Astro-5-Ökosystem-Stack: alle Integrationen (@astrojs/react, @astrojs/vue, @astrojs/mdx, @astrojs/sitemap, @astrojs/rss), alle Adapter, Astro DB, View Transitions und die experimentellen Features wie Server Islands (Astro 5). Ein einziger Prompt wie "baue mir einen Blog mit Content Collections, Kommentar-Funktion via Astro DB und View Transitions" generiert vollständig funktionierenden, deploybasierten Code.

Die Kombination aus Zero-JS-by-Default, typsicheren Content Collections, nahtlosem SSR und eingebautem ORM macht Astro 2026 zur stärksten Wahl für Marketing-Sites, Blogs, Dokumentationsportale und alle Anwendungen, bei denen Performance und Content im Vordergrund stehen. Claude Code versteht diesen Stack vollständig und kann komplette Astro-Projekte von der Konfiguration bis zum Deployment aufbauen — in einem Bruchteil der Zeit, die manuelle Entwicklung erfordert.

Astro-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges Astro-Modul mit Islands Architecture, Content Collections, Astro DB und Deployment auf Vercel/Cloudflare Pages.

14 Tage kostenlos testen →