Astro ist 2026 das bevorzugte Framework für Content-lastige Websites, Blogs, Dokumentationen und Marketing-Pages.
Das Killer-Feature: standardmäßig wird kein JavaScript an den Browser geliefert — nur dann, wenn es wirklich nötig ist.
Mit Claude Code lassen sich Astro-Projekte blitzschnell aufsetzen, Content Collections typsicher verwalten und React-, Vue- oder Svelte-Komponenten
gezielt als interaktive Islands einbinden.
Was du in diesem Guide lernst
- Astro Grundlagen: .astro-Dateiformat, Frontmatter, Template-Syntax & Zero-JS-Default
- Islands Architecture: Hydration-Strategien client:load, client:idle, client:visible
- Content Collections: Schema-Definition, Typsicherheit & getCollection()
- Routing & Pages: File-based Routing, dynamische Slugs & SSR-Modus
- Integrationen: React, Vue, Svelte, Tailwind, MDX, @astrojs/image
- View Transitions & Deploy: Morph-Animationen, ClientRouter, Vercel/Cloudflare
1. Astro Grundlagen: .astro-Dateiformat & Zero-JS-Default
Astro-Komponenten haben die Dateiendung .astro und bestehen aus zwei Teilen:
dem Component Script (Frontmatter zwischen ----Trennern) und dem Component Template (HTML-ähnliche Syntax darunter).
Der entscheidende Unterschied zu React oder Vue: Das Script läuft ausschließlich zur Build-Zeit auf dem Server — kein JavaScript landet standardmäßig im Browser.
Minimales .astro-File
// src/pages/index.astro
---
// Component Script — läuft NUR zur Build-Zeit (Node.js)
const title = 'Meine Astro-Website';
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
---
<!-- Component Template — JSX-ähnliche Syntax -->
<html lang="de">
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<ul>
{posts.map(post => (
<li><a href={`/posts/${post.slug}`}>{post.title}</a></li>
))}
</ul>
</body>
</html>
Astro.props & Komponenten-Komposition
Wiederverwendbare Astro-Komponenten empfangen Daten über Astro.props.
TypeScript-Interfaces machen Props vollständig typsicher.
// src/components/BlogCard.astro
---
interface Props {
title: string;
excerpt: string;
slug: string;
publishedAt: Date;
readTime?: number;
}
const { title, excerpt, slug, publishedAt, readTime = 5 } = Astro.props;
const formattedDate = new Intl.DateTimeFormat('de-DE', {
day: 'numeric', month: 'long', year: 'numeric'
}).format(publishedAt);
---
<article class="blog-card">
<h2><a href={`/blog/${slug}`}>{title}</a></h2>
<p>{excerpt}</p>
<footer>
<time datetime={publishedAt.toISOString()}>{formattedDate}</time>
<span>{readTime} min Lesezeit</span>
</footer>
</article>
<style>
/* Scoped CSS — automatisch nur für diese Komponente */
.blog-card { border: 1px solid #e2e8f0; border-radius: 8px; padding: 1.5rem; }
.blog-card h2 a { text-decoration: none; color: inherit; }
</style>
Build-Output: statisches HTML
# Astro-Projekt erstellen + bauen
npm create astro@latest my-site -- --template minimal --typescript strict
cd my-site
npm run build
# dist/ enthält reines, optimiertes HTML — kein JavaScript-Bundle
# Lighthouse Score: ~100 Performance out of the box
dist/
index.html # 2.1 KB (kein JS!)
blog/
mein-post/
index.html # Jede Route = statische HTML-Datei
Zero-JS by Default — Warum das wichtig ist
- Kein JavaScript = kein Parsing, kein Hydrations-Overhead im Browser
- Lighthouse Performance Score nahe 100 ohne manuelle Optimierung
- Core Web Vitals (LCP, CLS, FID) automatisch exzellent
- SEO: Suchmaschinen-Crawler lesen vollständiges HTML sofort
- JavaScript nur dort wo nötig — via Islands Architecture
2. Islands Architecture: Selektive Hydration
Islands
client:load
client:idle
client:visible
Das Herzstück von Astro ist die Islands Architecture: Die Seite ist statisches HTML, aber einzelne "Inseln"
können interaktive Framework-Komponenten (React, Vue, Svelte, Solid, Preact) sein — mit präziser Kontrolle darüber,
wann die Hydration stattfindet.
Hydration-Direktiven im Überblick
| Direktive |
Wann hydriert? |
Use Case |
client:load | Sofort beim Seitenload | Hero-Navigation, kritische Widgets |
client:idle | Wenn Browser idle (requestIdleCallback) | Footer-Chat, sekundäre Features |
client:visible | Wenn in Viewport sichtbar (IntersectionObserver) | Tief im Scroll liegende Widgets |
client:media | Wenn CSS Media Query matcht | Mobile-only Slider |
client:only | Nur im Browser, kein SSR | Chart.js, Maps, Browser-APIs |
React-Komponente als Island einbinden
// src/components/SearchWidget.tsx — Normale React-Komponente
import { useState, useCallback } from 'react';
interface SearchWidgetProps {
placeholder?: string;
onSearch: (query: string) => void;
}
export default function SearchWidget({ placeholder = 'Suchen...', onSearch }: SearchWidgetProps) {
const [query, setQuery] = useState('');
const handleSubmit = useCallback((e: React.FormEvent) => {
e.preventDefault();
onSearch(query);
}, [query, onSearch]);
return (
<form onSubmit={handleSubmit} className="search-form">
<input
type="search"
value={query}
onChange={e => setQuery(e.target.value)}
placeholder={placeholder}
/>
<button type="submit">Suchen</button>
</form>
);
}
// src/pages/blog/index.astro — Island einbinden
---
import SearchWidget from '../../components/SearchWidget';
import BlogCard from '../../components/BlogCard.astro';
---
<main>
<h1>Blog</h1>
<!-- client:visible = React-JS wird erst geladen wenn Widget sichtbar -->
<SearchWidget
client:visible
placeholder="Artikel suchen..."
onSearch={query => console.log(query)}
/>
<!-- Statische Astro-Komponenten — kein JS -->
<div class="grid">
<BlogCard title="Erster Post" slug="erster-post" excerpt="..." publishedAt={new Date()} />
</div>
</main>
client:only — Browser-exklusive Komponenten
// Für Komponenten die auf Browser-APIs angewiesen sind (window, document, localStorage)
// client:only verhindert SSR-Fehler und lädt nur im Browser
---
import MapComponent from '../components/MapComponent';
import ChartDashboard from '../components/ChartDashboard';
---
<!-- "react" teilt Astro mit welches Framework-Runtime geladen werden soll -->
<MapComponent client:only="react" center={[52.52, 13.405]} />
<!-- Svelte-Komponente als Island -->
<ChartDashboard client:only="svelte" data={analyticsData} />
3. Content Collections: Typsichere Inhalte mit Zod
Collections
MDX
Zod Schema
Content Collections sind Astros Antwort auf die Frage: "Wie verwalte ich strukturierte Inhalte typsicher?"
Mit defineCollection und Zod-Schemas werden alle Markdown/MDX-Frontmatter-Felder zur Build-Zeit validiert —
fehlendes Pflichtfeld = Build-Fehler, keine Runtime-Überraschungen.
Collection Schema definieren
// src/content/config.ts — Zentrale Konfiguration aller Collections
import { defineCollection, z } from 'astro:content';
const blogCollection = defineCollection({
type: 'content', // 'content' für MD/MDX, 'data' für JSON/YAML
schema: z.object({
title: z.string().max(80),
description: z.string().max(160),
publishedAt: z.coerce.date(),
updatedAt: z.coerce.date().optional(),
author: z.string().default('SpockyMagicAI'),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
image: z.object({
src: z.string(),
alt: z.string(),
}).optional(),
readTime: z.number().positive().optional(),
}),
});
const docsCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
sidebar: z.object({ order: z.number(), label: z.string().optional() }),
category: z.enum(['guide', 'reference', 'tutorial']),
}),
});
export const collections = {
blog: blogCollection,
docs: docsCollection,
};
Markdown-Frontmatter mit Schema
# src/content/blog/astro-guide.md
---
title: "Astro Anfänger-Guide 2026"
description: "Alles über Astro: Islands, Collections und Performance"
publishedAt: "2026-05-06"
author: "Daniel Bratschke"
tags: ["astro", "performance", "ssg"]
readTime: 8
image:
src: "/images/astro-cover.jpg"
alt: "Astro Framework Logo auf dunklem Hintergrund"
---
Astro ist das schnellste Framework für content-lastige Websites...
getCollection() & getEntry() — Typsichere Abfragen
// src/pages/blog/index.astro
---
import { getCollection, getEntry } from 'astro:content';
// Alle Posts laden — drafts in Produktion herausfiltern
const allPosts = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});
// Nach Datum sortieren (neueste zuerst)
const sortedPosts = allPosts.sort(
(a, b) => b.data.publishedAt.getTime() - a.data.publishedAt.getTime()
);
// Einen einzelnen Eintrag laden
const featuredPost = await getEntry('blog', 'astro-guide');
---
{sortedPosts.map(post => (
<article>
<h2><a href={`/blog/${post.slug}`}>{post.data.title}</a></h2>
<p>{post.data.description}</p>
<time>{post.data.publishedAt.toLocaleDateString('de-DE')}</time>
{post.data.tags.map(tag => <span class="tag">{tag}</span>)}
</article>
))}
4. Routing & Pages: File-based Routing & SSR
File Routing
SSR
API Routes
Astro folgt dem File-System-basierten Routing-Prinzip: Jede Datei in src/pages/ wird zur Route.
Für dynamische Routen wie Blog-Posts oder Produkt-Seiten generiert getStaticPaths() alle möglichen Slugs zur Build-Zeit.
Dynamische Routen mit getStaticPaths()
// src/pages/blog/[slug].astro
---
import { getCollection } from 'astro:content';
import BlogLayout from '../../layouts/BlogLayout.astro';
import { Image } from 'astro:assets';
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, headings, remarkPluginFrontmatter } = await post.render();
---
<BlogLayout title={post.data.title} description={post.data.description}>
<header>
<h1>{post.data.title}</h1>
{post.data.image && (
<Image
src={post.data.image.src}
alt={post.data.image.alt}
width={1200} height={630}
format="webp"
/>
)}
</header>
<!-- Content rendert den Markdown/MDX-Inhalt -->
<Content />
</BlogLayout>
SSR-Modus: Server-seitige Requests
// astro.config.mjs — SSR aktivieren
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server', // 'static' | 'hybrid' | 'server'
adapter: vercel(),
});
// 'hybrid' = SSG default, einzelne Pages opt-in SSR:
// export const prerender = false; // in der jeweiligen Page
API-Endpoints in Astro
// src/pages/api/subscribe.ts — REST-Endpoint
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
const { email } = body;
if (!email || !email.includes('@')) {
return new Response(JSON.stringify({ error: 'Ungültige E-Mail' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// Zur Mailchimp/Resend API senden...
const result = await addToMailingList(email);
return new Response(JSON.stringify({ success: true, id: result.id }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};
Routing-Muster in Astro
src/pages/index.astro → /
src/pages/blog/index.astro → /blog/
src/pages/blog/[slug].astro → /blog/:slug (dynamisch)
src/pages/blog/[...path].astro → /blog/* (catch-all)
src/pages/api/subscribe.ts → /api/subscribe (REST)
src/pages/rss.xml.ts → /rss.xml (RSS Feed)
5. Integrationen: React, Vue, Svelte, Tailwind & MDX
React
Vue
Svelte
Tailwind
Astro's Integrations-System macht es trivial, beliebte Frameworks und Tools hinzuzufügen.
Der astro add-Befehl konfiguriert alles automatisch — inklusive TypeScript-Definitionen.
Integrationen installieren
# Framework-Integrationen (können kombiniert werden!)
npx astro add react # React 18 + JSX-Transform
npx astro add vue # Vue 3 Composition API
npx astro add svelte # Svelte 5 (Runes-Syntax)
npx astro add preact # Preact — minimales React-kompatibles Framework
npx astro add solid-js # Solid.js — reaktiv, kein VDOM
# CSS & Styling
npx astro add tailwind # Tailwind CSS v4 + PostCSS
# Content & SEO
npx astro add mdx # MDX — Markdown + JSX/React-Komponenten
npx astro add sitemap # Automatische sitemap.xml Generierung
# Bild-Optimierung
npx astro add @astrojs/image # WebP/AVIF Konvertierung + lazy loading
astro.config.mjs — Mehrere Integrationen
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import vue from '@astrojs/vue';
import tailwind from '@astrojs/tailwind';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://meine-website.de',
integrations: [
react(),
vue(),
tailwind({ applyBaseStyles: false }),
mdx({
syntaxHighlight: 'shiki',
shikiConfig: { theme: 'github-dark' },
remarkPlugins: [remarkReadingTime],
rehypePlugins: [rehypeAutolinkHeadings],
}),
sitemap({
filter: page => !page.includes('/draft/'),
changefreq: 'weekly',
priority: 0.7,
}),
],
image: {
service: { entrypoint: 'astro/assets/services/sharp' },
},
vite: {
plugins: [],
build: { cssCodeSplit: true },
},
});
MDX: Markdown mit Komponenten
{/* src/content/blog/mdx-beispiel.mdx */}
---
title: MDX in Astro — Interaktive Docs
publishedAt: 2026-05-06
---
import CodePlayground from '../../components/CodePlayground';
import Callout from '../../components/Callout.astro';
## Normale Markdown-Überschrift
Normaler Markdown-Text mit **Bold** und _Italic_.
<Callout type="warning">
MDX erlaubt es, React/Astro-Komponenten direkt im Markdown zu nutzen!
</Callout>
<CodePlayground
client:visible
code={`const greeting = 'Hallo Astro!';
console.log(greeting);`}
/>
## Weiter mit normalem Markdown...
@astrojs/image — Automatische Bildoptimierung
---
import { Image, Picture } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<!-- Automatisch: WebP-Konvertierung, lazy loading, korrekte width/height -->
<Image
src={heroImage}
alt="Hero Bild"
width={1200}
height={630}
format="webp"
quality={85}
loading="lazy"
/>
<!-- Picture = automatische Art-Direction + mehrere Formate -->
<Picture
src={heroImage}
alt="Responsive Hero"
formats={['avif', 'webp']}
widths={[400, 800, 1200]}
/>
6. View Transitions & Deploy: Smooth Navigation & Production
View Transitions
Vercel
Cloudflare
Astro's View Transitions API verwandelt eine statische Multi-Page-App (MPA) in eine SPA-ähnliche Erfahrung
mit flüssigen Seitenübergängen — ohne das gesamte JavaScript-Bundle einer echten SPA laden zu müssen.
Der ClientRouter übernimmt die Navigation und animiert DOM-Elemente automatisch.
ClientRouter & transition:animate
// src/layouts/BaseLayout.astro — View Transitions global aktivieren
---
import { ClientRouter } from 'astro:transitions';
interface Props {
title: string;
}
const { title } = Astro.props;
---
<html lang="de">
<head>
<title>{title}</title>
<!-- Aktiviert MPA View Transitions für alle Seitenwechsel -->
<ClientRouter />
</head>
<body>
<slot />
</body>
</html>
// src/pages/blog/[slug].astro — Morphing-Animation für Hero-Bild
---
import { Image } from 'astro:assets';
const { post } = Astro.props;
---
<!-- transition:name = eindeutiger Key für Morph-Animation -->
<h1 transition:name={`title-${post.slug}`}>{post.data.title}</h1>
<Image
src={post.data.image.src}
alt={post.data.image.alt}
width={1200} height={630}
transition:name={`hero-${post.slug}`}
/>
<!-- Benutzerdefinierte Animation -->
<aside transition:animate="slide">
Sidebar-Inhalt gleitet rein
</aside>
<main transition:animate="fade">
Hauptinhalt blendet über
</main>
Custom View Transition Animations
// Eigene Animationen mit CSS @keyframes
---
import { fade, slide } from 'astro:transitions';
---
<!-- Built-in Animationen -->
<div transition:animate={fade({ duration: '0.3s' })}>...</div>
<div transition:animate={slide({ duration: '0.25s' })}>...</div>
<style>
/* Eigene Animation per CSS */
::view-transition-old(hero-image) {
animation: 200ms ease-in-out both scale-out;
}
::view-transition-new(hero-image) {
animation: 300ms ease-in-out both scale-in;
}
@keyframes scale-out {
from { transform: scale(1); }
to { transform: scale(0.95); opacity: 0; }
}
@keyframes scale-in {
from { transform: scale(0.95); opacity: 0; }
to { transform: scale(1); }
}
</style>
Deployment: Vercel, Netlify & Cloudflare
# Vercel (empfohlen für SSR + Edge Functions)
npx astro add @astrojs/vercel
# astro.config.mjs: adapter: vercel(), output: 'server'
vercel deploy
# Netlify (SSR via Netlify Functions)
npx astro add @astrojs/netlify
# astro.config.mjs: adapter: netlify()
netlify deploy --prod
# Cloudflare Pages (Edge Runtime — schnellstes Deploy)
npx astro add @astrojs/cloudflare
# astro.config.mjs: adapter: cloudflare({ mode: 'directory' })
npx wrangler pages deploy ./dist
# Statisches Deploy (output: 'static') — kein Adapter nötig
npm run build
# dist/ auf beliebiges CDN: S3, GitHub Pages, Surge.sh...
Claude Code & Astro: Optimaler Workflow
# Claude Code generiert komplette Astro-Projekte in Minuten:
# 1. Projektstruktur + Config
claude code "Erstelle ein Astro-Blog mit TypeScript, Tailwind, MDX und React-Islands.
Konfiguriere Content Collections mit Zod-Schema für Posts mit title, description,
publishedAt, tags, image (optional), draft. Füge SEO-Layout mit OG-Tags hinzu."
# 2. Einzelne Komponenten
claude code "Erstelle eine Astro-Seite src/pages/blog/[slug].astro die:
- getStaticPaths() mit getCollection('blog') nutzt
- View Transitions mit transition:name für Titel + Hero-Bild hat
- Ein Reading-Progress-Bar als React-Island (client:load) einbindet"
# 3. Spezifische Features
claude code "Füge RSS Feed (src/pages/rss.xml.ts) und Sitemap-Integration hinzu.
Generiere außerdem einen automatischen OG-Image-Generator als API-Route."
Astro — Ideal für
- Blogs & Content-Seiten
- Marketing-Landing-Pages
- Dokumentations-Portale
- E-Commerce Produktseiten
- Portfolio-Websites
- SEO-kritische Projekte
Weniger geeignet für
- Hochinteraktive Web-Apps
- Real-time Dashboards
- Chat-Applikationen
- Komplexe SPA-Flows
- Browser-Games
- Collaboration-Tools
Performance-Vergleich: Astro vs. Next.js vs. Nuxt
- Astro (SSG): LCP ~0.4s, TBT 0ms, JS-Bundle 0 KB (kein Framework JS)
- Next.js (SSG): LCP ~0.8s, TBT 50ms, JS-Bundle ~85 KB (React Runtime)
- Nuxt (SSG): LCP ~0.9s, TBT 80ms, JS-Bundle ~105 KB (Vue Runtime)
- Astro (mit 1 React Island): LCP ~0.5s, TBT 15ms, JS ~45 KB
- Quelle: Web Almanac Performance Benchmarks, Q1 2026
Astro-Projekte mit Claude Code automatisieren
Islands Architecture, typsichere Content Collections, View Transitions und optimales Deployment —
Claude Code versteht die moderne Astro-Architektur und generiert produktionsreifen Code für blitzschnelle Websites.
Jetzt kostenlos testen und die erste Astro-Site in Minuten aufsetzen.
14 Tage kostenlos testen →