Entdeckt die Vorteile von Astro JS Islands für eure Webprojekte. Unsere Experten bieten fundierte Beratung und Schulungen zur effizienten Implementierung dieser leistungsstarken Architektur.
Mehr erfahren
Der Astro Static Site Build ist der Schritt, in dem astro build dein Projekt in fertige Dateien übersetzt. Das Ergebnis landet im dist Ordner: HTML pro Seite, gebündeltes CSS und JavaScript mit Hash im Namen und alle Dateien aus public.
Wie der Ordner aussieht, entscheidet ein Detail: Ist ein Adapter konfiguriert oder nicht? Ohne Adapter bekommst du eine flache Struktur. Mit Adapter teilt Astro den Output in client und server.
Wer die Struktur kennt, schreibt saubere Deploy Skripte, findet fehlende Assets schneller und setzt Cache Header richtig. Hier siehst du den Aufbau für Astro 7, die Stellschrauben in der Config und die typischen Fehler aus der Praxis.
Astro gehört bei uns zum Production Stack. Wir bauen damit Frontends neben Sulu CMS und Symfony, mit TypeScript, Tailwind CSS und Drizzle für die Datenschicht. Die Builds laufen in GitHub Actions oder GitLab CI und landen auf eigenen Servern in Deutschland. Roland Golla arbeitet seit über 20 Jahren an Softwarequalität und ist Cypress Ambassador. Deshalb prüft bei uns die Pipeline jeden Build Output, bevor er live geht.
Passend dazu unterstützen wir bei Frontend Development mit Astro, bei Astro Islands und Performance Architektur und beim Astro Script Tag für Production. Für die Datenbank im Projekt zeigen wir SQLite und Drizzle statt Astro DB. Wer KI Agenten am Frontend arbeiten lässt, findet bei den NCA Agentic AI Coding Guardrails den Rahmen mit Quality Gates.
Remote und als Live Demo: Mit OpenCode und kostenlosen, lokalen Modellen entsteht eine Astro Landing Page von der leeren Mappe bis zum Deploy unter eigener URL. Wir gehen die OneShot Best Practice Datei Zeile für Zeile durch und sichern den Code mit statischer Analyse, curl Checks und Cypress Tests ab. Kein bezahltes US Abo, keine Installation vorab.
Ohne Adapter und mit dem Default output: 'static' rendert Astro jede Seite beim Build zu HTML. Die Ordner spiegeln dein Routing aus src/pages. Mit dem Default build.format: 'directory' wird aus about.astro die Datei about/index.html.
dist/
├── index.html
├── about/
│ └── index.html
├── blog/
│ ├── index.html
│ └── erster-beitrag/
│ └── index.html
├── _astro/
│ ├── Layout.CkF3s9xA.css
│ └── index.DRf8L97S.js
├── robots.txt # aus public/
└── favicon.svg # aus public/
JavaScript taucht nur auf, wenn eine Komponente es braucht, etwa über eine client: Direktive oder ein Script Tag. Eine reine Content Seite kommt ganz ohne JS Datei aus. Mit build.format: 'file' erzeugst du stattdessen about.html. Das passt zu Servern, die ohne Trailing Slash arbeiten.
Sobald ein Adapter wie @astrojs/node im Spiel ist, ändert sich das Bild. Astro schreibt den Browser Teil nach dist/client und den Server Teil nach dist/server. Die Namen steuerst du über build.client und build.server.
dist/
├── client/
│ ├── _astro/
│ │ ├── Layout.CkF3s9xA.css
│ │ └── Counter.B3kLm9Qe.js
│ ├── index.html # prerenderte Seite
│ └── favicon.svg
└── server/
├── entry.mjs # Einstieg für die Runtime
└── ... # gebündelter Server Code
entry.mjs ist der Startpunkt, den Node oder die Plattform ausführt. Den Namen setzt meist der Adapter über build.serverEntry. Seiten mit Prerendering liegen als fertiges HTML in client. Alles, was pro Request gerendert wird, steckt im Server Bundle.
Achtung: Auch bei output: 'static' kann ein Adapter die Aufteilung behalten. Seit Astro 6.4 legen Adapter über preserveBuildClientDir und preserveBuildServerDir fest, dass das Layout immer gleich bleibt. Wer rein statisch deployen will, prüft deshalb zuerst, ob ein Adapter in der Config steht.
Der Name _astro ist nur ein Default. Über build.assets änderst du ihn. Das hilft bei Hostern, die Ordner mit Unterstrich ignorieren, und bei festen Pfaden im CDN.
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
build: {
assets: 'assets',
assetsPrefix: 'https://cdn.example.com'
}
});
Der Hash im Dateinamen entsteht aus dem Inhalt. Ändert sich eine Datei, ändert sich ihr Name. Deshalb darfst du alles unter _astro mit sehr langen Cache Headern ausliefern. HTML bekommt kurze Cache Zeiten, weil es auf die neuen Dateinamen zeigt.
Mit assetsPrefix zeigen alle Asset Links auf eine eigene Domain. Statt eines Strings geht auch ein Objekt mit einer Domain pro Dateityp und dem Pflichtfeld fallback.
Für volle Kontrolle über Dateinamen nutzt Astro die Rollup Optionen von Vite. Die offizielle Doku setzt sie für den Client Build unter vite.environments.client:
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
vite: {
environments: {
client: {
build: {
rollupOptions: {
output: {
entryFileNames: 'js/[name]-[hash].js',
chunkFileNames: 'js/chunks/[name]-[hash].js',
assetFileNames: 'static/[name]-[hash][extname]'
}
}
}
}
}
}
});
Seit Astro 7 bündelt Vite 8 mit Rolldown. Bestehende rollupOptions übersetzt eine Kompatibilitätsschicht automatisch. Den Platzhalter [hash] solltest du immer behalten, sonst funktioniert Cache Busting nicht mehr. Dateien aus public bleiben von allen Namensregeln unberührt.
Astro 7 ist ein Release für Geschwindigkeit. Die Ordner im dist bleiben gleich, der Inhalt der Dateien kann sich ändern. Diese Punkte solltest du nach dem Upgrade prüfen:
'jsx'. Leerzeichen zwischen Inline Elementen auf getrennten Zeilen fallen weg. Wer das alte Verhalten will, setzt compressHTML: true.@astrojs/markdown-remark mit dem unified() Processor.url() Angaben können anders geschrieben sein. Optisch ändert sich nichts, String Vergleiche in Tests schlagen aber an.Für Visual Regression lohnt sich ein Vergleich vor und nach dem Upgrade. Wir nutzen dafür BackstopJS und lassen Cypress gegen den gebauten Output laufen.
Astro legt Zwischenstände in cacheDir ab, Default ist node_modules/.astro. Mit dem experimentellen Flag incrementalBuild aus Astro 7.2 überspringt Astro Seiten, deren Daten und Code sich nicht geändert haben. Statt neu zu rendern, kopiert es den alten Output.
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
incrementalBuild: true
}
});
Damit das greift, braucht jede Seite aus getStaticPaths() einen cacheKey, etwa einen Zeitstempel aus dem CMS oder den digest eines Content Collection Eintrags. Der dist Ordner wird trotzdem bei jedem Build geleert. Übersprungene Seiten stellt Astro aus dem Cache wieder her.
cacheDir. Fehlt er, rendert Astro alles neu.astro build --force ignoriert den Cache und schreibt einen frischen.--force bauen.build.concurrency größer 1 ist der Cache deaktiviert.Weil das Feature experimentell ist, aktivieren wir es nur mit Tests in der Pipeline. Ein falscher cacheKey liefert sonst veraltete Seiten aus.
The fastest build is the one that doesn’t happen at all.
In der Praxis läuft astro build selten lokal. Bei uns baut die Pipeline, testet den Output und deployt erst danach. Bei Static Output reicht es, den Inhalt von dist auf den Webserver zu kopieren.
# GitHub Actions: Build, Test, Deploy
- name: Build
run: |
npm ci
npm run build
- name: E2E Tests gegen den Build
run: |
npx astro preview --port 4321 &
npx wait-on http://localhost:4321
npx cypress run --record
- name: Deploy
run: rsync -avz --delete dist/ deploy@server:/var/www/site/
Für Container reicht ein Multi Stage Build. Node baut, ein schlanker Webserver liefert aus.
# Dockerfile für Static Output
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
Bei Server Output braucht dist/server zur Laufzeit die Production Dependencies. Kopiere deshalb neben dem dist Ordner auch die installierten Node Module ins Ziel Image und starte mit node ./dist/server/entry.mjs. Mehr zu Containern steht im Docker Glossar, zu Gates in der Pipeline bei den NCA Agentic AI Coding Guardrails.
_astro. Lege eine leere .nojekyll Datei in public ab oder benenne den Ordner über build.assets um.client und server erzeugen, obwohl alles statisch ist. Das Deploy Skript findet dann kein index.html im Root.public bekommen keinen Hash und keine Optimierung. Lange Cache Header sind dort riskant.compressHTML mit JSX Regeln. Setze das Leerzeichen explizit mit {" "}.base gesetzt sein. Sonst zeigen die Links auf /_astro im Root und laufen ins Leere.Viele dieser Fehler fallen erst im Browser auf. Deshalb prüfen wir gebaute Seiten mit Cypress und axe core, so wie bei den Accessibility Testing Tools beschrieben. Ladezeiten messen wir mit echten Felddaten aus dem CrUX Report für Core Web Vitals.
Entdeckt die Vorteile von Astro JS Islands für eure Webprojekte. Unsere Experten bieten fundierte Beratung und Schulungen zur effizienten Implementierung dieser leistungsstarken Architektur.
Mehr erfahrenBei Never Code Alone geht ein Astro Projekt erst live, wenn die Pipeline grün ist. Vor dem Build laufen TypeScript im strict Mode, Unit Tests mit Vitest, Mutation Testing mit StrykerJS und die Suche nach totem Code mit Knip. Danach prüft Cypress mit Cypress Cloud den fertigen Output im Browser.
Fürs Styling nutzen wir Tailwind CSS, für Validierung Zod 4. Content kommt aus Sulu CMS oder, bei schlanken Projekten, aus Obsidian als CMS für Astro. Liefern alte Frontends zu viel JavaScript aus, hilft unser Ansatz JavaScript ablösen für Barrierefreiheit und Performance. Gehostet wird auf eigenen Servern in Deutschland, die Infrastruktur stellt unser Netzwerkpartner Conversis in Duisburg.
Neben dem Frontend beraten wir im PHP Consulting zu Symfony und Sulu und im Vibe Coding Consulting für Teams, die KI Agenten sicher in Production bringen wollen. Alle Frontend Themen findest du in der Übersicht Frontend Development. Einen Einstieg in das Framework selbst gibt Astro als Static Site Generator.
Wir bauen schnelle, sichere und barrierefreie Websites mit Astro. Kurze Ladezeiten, saubere Technik und gute Bedienbarkeit für alle, so erfüllt eure Website die gesetzlichen Anforderungen und wird gleichzeitig besser gefunden. Jede Änderung prüfen automatisierte Tests, bevor sie live geht.
Die wichtigsten Fragen zum Astro Static Site Build und zur dist Ordner Struktur, kurz und direkt beantwortet.
Ohne Adapter erzeugt astro build einen flachen dist Ordner. HTML Dateien liegen im Root und spiegeln das Routing aus src/pages. Gebündeltes CSS, JavaScript und optimierte Bilder landen mit Content Hash im Unterordner _astro. Dateien aus public kopiert Astro unverändert in den Root. Mit Adapter teilt Astro den Output in dist/client und dist/server.
Der _astro Ordner enthält alles, was durch die Build Pipeline läuft: gebündeltes CSS, JavaScript Chunks und optimierte Bilder. Jede Datei trägt einen Hash im Namen, der aus dem Inhalt berechnet wird. Ändert sich der Inhalt, ändert sich der Name. Den Ordnernamen änderst du über build.assets in der astro.config.mjs.
Die Aufteilung entsteht, sobald ein Adapter konfiguriert ist. dist/client enthält statische Assets und prerenderte Seiten, dist/server den Code für das Rendern pro Request mit entry.mjs als Einstieg. Adapter können dieses Layout auch für statische Builds behalten. Wer rein statisch deployen will, entfernt deshalb den Adapter aus der Config.
Die Ordnerstruktur bleibt gleich, der Inhalt kann sich ändern. Der Rust Compiler korrigiert kein ungültiges HTML mehr. compressHTML entfernt Leerzeichen jetzt nach JSX Regeln. Markdown läuft über Sätteri statt remark und rehype. CSS Werte können anders serialisiert sein. Gebündelt wird mit Vite 8 und Rolldown, was Builds deutlich schneller macht.
Cache in der Pipeline den Ordner cacheDir, standardmäßig node_modules/.astro. Mit dem experimentellen Flag incrementalBuild überspringt Astro Seiten aus getStaticPaths, wenn cacheKey und Code unverändert sind. Dazu kommt das Upgrade auf Astro 7, das laut Astro Team in Benchmarks 15 bis 61 Prozent schneller baut. Den dist Ordner selbst cachst du nicht.
Das Zielverzeichnis setzt du mit outDir in der astro.config.mjs, der Default ist ./dist. Bei Server Output bestimmen build.client und build.server die Unterordner, jeweils relativ zu outDir. Den Namen des Assets Ordners steuert build.assets. Mit build.format legst du fest, ob about.html oder about/index.html entsteht.
Über die Rollup Optionen von Vite unter vite.environments.client.build.rollupOptions.output. Mit entryFileNames, chunkFileNames und assetFileNames legst du Muster wie js/[name]-[hash].js fest. Den Platzhalter [hash] solltest du behalten, sonst funktioniert Cache Busting nicht mehr. Dateien aus public sind von diesen Regeln nicht betroffen.
GitHub Pages nutzt Jekyll, und Jekyll ignoriert Ordner mit Unterstrich. Ohne Gegenmaßnahme ist _astro dann nicht erreichbar. Lege eine leere .nojekyll Datei in public ab oder benenne den Assets Ordner über build.assets um. Liegt die Seite in einem Unterpfad des Repositorys, setzt du zusätzlich base in der Config.
Alle. Astro kopiert den public Ordner beim Build unverändert in den Root von dist. Es gibt keinen Hash, keine Minifizierung und keine Bildoptimierung. Das passt für robots.txt, Favicon und Dateien mit festem Namen. Bilder, CSS und Scripts gehören besser nach src, damit Astro sie optimiert und mit Hash versieht.
Dateien unter _astro tragen einen Content Hash und ändern bei jeder Änderung ihren Namen. Sie bekommen deshalb sehr lange Cache Zeiten mit immutable. HTML Dateien zeigen auf diese Namen und brauchen kurze Cache Zeiten oder Revalidierung. Für Dateien aus public ohne Hash wählst du moderate Werte, weil sich ihr Name nie ändert.
Ja. Mit output static und Adapter bleiben Seiten standardmäßig prerendert. Einzelne Seiten stellst du mit export const prerender = false auf Rendern pro Request um. Bei output server ist es umgekehrt, dort markierst du statische Seiten mit prerender = true. Im Build landen prerenderte Seiten als HTML in client, dynamische im Server Bundle.
Wir richten Astro Builds in GitHub Actions oder GitLab CI ein, mit TypeScript Checks, Vitest, Cypress und sauberem Caching. Deployt wird auf eigene Server in Deutschland oder in eure Infrastruktur. Am Anfang steht ein kostenloses Kennenlernen, danach schätzen wir den Aufwand und rechnen minutengenau ab, ohne Pakete und ohne Festpreis.