„Wo legen wir die Bilder eigentlich hin?“ – diese Frage kommt in jedem frischen Astro Projekt innerhalb der ersten Stunde. Kein CMS im Spiel, nur ein leeres Verzeichnis und die Entscheidung zwischen zwei Ordnern. Die gute Nachricht: Astro kennt genau zwei Orte, und die Trennung ist einfacher als sie in den meisten Diskussionen klingt.
src/assets für alles, was zu eurem Content oder Layout gehört. public nur für Dateien, die eine feste, ratbare URL brauchen. Alles Weitere ergibt sich daraus von allein.
Vibe Coding Schulung: in zwei Stunden zur deployten Landing Page
Remote, ohne US Abo, mit OpenCode und lokalen Modellen. Ihr baut live mit, statt zuzuschauen.
- Astro Projekt von der leeren Mappe bis zum Deployment
- OpenCode im Terminal, lokale Modelle über Ollama
- Daten bleiben im eigenen Netz, kein Abo bei US Anbietern
- Danach laufende Begleitung statt Zertifikat und tschüss
src/assets ist der Default
Alles in src/assets läuft durch die Build Pipeline. Das ist kein Nice to have, sondern der eigentliche Grund für diesen Ordner:
- Konvertierung nach WebP und AVIF
- Responsive Größen aus einer einzigen Quelldatei
- Dateinamen mit Content Hash, also sauberes Cache Busting
- Breite und Höhe werden automatisch gesetzt, kein Layout Shift
- Der Build bricht ab, wenn ein Pfad kaputt ist. Genau das wollt ihr.
So sieht die Struktur aus, die sich in der Praxis bewährt:
src/
assets/
blog/ # Bilder pro Post, benannt wie der Slug
astro-setup/
hero.png
screenshot-1.png
images/ # geteilt: Logos, Autoren Avatare, Icons
content/
blog/
astro-setup.md
public/
favicon.svg
og-default.png
robots.txt
Eingebunden wird über die Image Komponente aus astro:assets:
---
import { Image } from 'astro:assets';
import hero from '../assets/blog/astro-setup/hero.png';
---
<Image src={hero} alt="Astro Setup" widths={[400, 800, 1200]} />
Der Import ist der entscheidende Teil. Astro kennt die Datei zur Buildzeit, prüft sie und optimiert sie. Ein String Pfad kann das nicht leisten.
public nur für feste URLs
In public gehört, was von außen unter einer bekannten Adresse erreichbar sein muss: favicon.svg, robots.txt, og-default.png, PDFs, alles was ein externer Dienst direkt verlinkt. Diese Dateien werden eins zu eins kopiert. Keine Optimierung, kein Hash im Namen, kein Fehler beim Build wenn der Pfad ins Leere zeigt.
Das Open Graph Bild ist das beste Beispiel. LinkedIn und Co. holen es sich per URL, lange bevor irgendein Template es importiert hätte. Also public.
Die Faustregel
Importiert ein Template oder eine Markdown Datei die Datei, gehört sie nach src/assets. Fragt etwas außerhalb eures Builds sie per URL an, gehört sie nach public. Mehr Entscheidungslogik braucht ihr nicht.
Zwei Dinge, die ihr früh einrichtet
Bilder pro Post zusammenlegen. Ein Ordner assets/blog/<slug>/ je Beitrag. Fliegt der Post raus, fliegt der Ordner mit raus. Ohne diese Struktur sammelt ihr nach einem Jahr Bilder, bei denen niemand mehr weiß, ob sie noch irgendwo hängen.
image() ins Collection Schema. Damit werden Cover Bilder aus dem Frontmatter beim Build validiert, statt still ins Leere zu zeigen:
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: ({ image }) => z.object({
title: z.string(),
cover: image(),
coverAlt: z.string(),
}),
});
export const collections = { blog };
Der Alt Text als Pflichtfeld daneben kostet nichts und rettet euch später die Barrierefreiheit. Die Details stehen in der Astro Dokumentation zu Bildern und im Abschnitt zu Content Collections.
Fazit
Zwei Ordner, eine Regel. Wer das am ersten Tag richtig aufsetzt, spart sich später die Migration von hundert Bildern aus public in die Pipeline. Genau solche Entscheidungen trifft ein KI Agent gern falsch, wenn niemand sie vorgibt. Deshalb gehören sie in die Projektregeln, bevor der erste Prompt läuft. Wie das im Alltag aussieht, steht im Überblick zu Vibe Coding und bei den Vibe Coding Best Practices.
Astro und OpenCode live lernen
In der NCA Vibe Coding Schulung startet ihr mit einer leeren Mappe und endet mit einer deployten Astro Seite. Struktur, Guardrails und Deployment inklusive. Termine auf Anfrage, kostenloses Kennenlernen vorab, danach transparente Minuten Abrechnung.
