Starlight & Astro Blog Best Practices
Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.
Starlight & Astro Blog Best Practices
Section titled “Starlight & Astro Blog Best Practices”Overview
Section titled “Overview”This document details best practices for implementing a blog using Starlight and Astro, based on research into the starlight-blog plugin and Astro’s content collections and routing systems.
Starlight-Blog Plugin Configuration
Section titled “Starlight-Blog Plugin Configuration”1. Content Collections Configuration
Section titled “1. Content Collections Configuration”The starlight-blog plugin requires the docs collection to be extended with blogSchema. This is done in src/content.config.ts:
import { defineCollection } from 'astro:content';import { docsLoader } from '@astrojs/starlight/loaders';import { docsSchema } from '@astrojs/starlight/schema';import { blogSchema } from 'starlight-blog/schema';
export const collections = { docs: defineCollection({ loader: docsLoader(), schema: docsSchema({ extend: (context) => blogSchema(context), }), }),};2. Starlight-Blog Integration Configuration
Section titled “2. Starlight-Blog Integration Configuration”The starlight-blog plugin is added as an integration in astro.config.mjs:
import { defineConfig } from 'astro/config';import starlight from '@astrojs/starlight';import starlightBlog from 'starlight-blog';
export default defineConfig({ site: 'https://your-site.com', trailingSlash: 'never', integrations: [ starlight({ title: "Your Site Title", defaultLocale: 'root', locales: { root: { label: 'Deutsch', lang: 'de', prefixDefaultLocale: false }, en: { label: 'English', lang: 'en' }, }, customCss: ['./src/styles/global.css'], sidebar: [ // ... sidebar items ], }), starlightBlog({ authors: { 'author-id': { name: 'Author Name', }, }, metrics: { readingTime: true, words: 'rounded', }, navigation: 'header-end', prefix: 'blog', postCount: 10, recentPostCount: 10, rss: true, title: 'Blog', }), ],});Astro Route Matching and Catch-All Segments
Section titled “Astro Route Matching and Catch-All Segments”The Issue with '[...prefix]/[...page]' Pattern
Section titled “The Issue with '[...prefix]/[...page]' Pattern”The starlight-blog plugin injects the blog list page route with the pattern '/[...prefix]/[...page]'. In Astro’s route matching:
prefixis a catch-all segmentpageis a catch-all segment
For the blog list page at /blog, the page parameter is undefined. In Astro’s route matching, a pattern with '[...page]' catch-all segment doesn’t correctly match the root blog prefix when page is undefined, which can cause the server to return a 403 or 404 error.
Best Practice for Blog List Page
Section titled “Best Practice for Blog List Page”To ensure the blog list page is generated correctly, the starlight-blog plugin’s getBlogStaticPaths() function generates paths with:
params: { page: index === 0 ? undefined : `${index + 1}`, prefix: getPathWithLocale(config.prefix, locale),}For index 0 (the blog list page), page is undefined, and prefix is blog (or en/blog for English).
Blog Post File Structure
Section titled “Blog Post File Structure”Blog posts should be placed in the src/content/docs/blog/ directory with the following structure:
src/content/docs/blog/├── 2026-07-06-stable-diffusion-bilder-generieren.md└── ...Each blog post should have the following frontmatter:
---title: 'Stable Diffusion - Bilder generieren mit FLUX.2-klein-4B'description: 'Best practices for implementing a blog using Starlight and Astro, based on research into the starlight-blog plugin and Astro content collections'date: 2026-07-02status: verifieddate: 2026-07-06authors: - michael-wegener - jane-alesi---
# Stable Diffusion - Bilder generieren mit FLUX.2-klein-4B
...Known Issues and Workarounds
Section titled “Known Issues and Workarounds”Blog List Page 403 Error
Section titled “Blog List Page 403 Error”When the starlight-blog plugin’s Blog.astro route pattern '/[...prefix]/[...page]' doesn’t correctly match the blog list page when page is undefined, the server may return a 403 or 404 error.
Workaround: Create a custom blog list page component at src/routes/blog/index.astro with explicit /blog route pattern, or update the starlight-blog plugin’s route injection to handle the blog list page correctly.
References
Section titled “References”Serving the Site Locally
Section titled “Serving the Site Locally”For Users: Manual Development Session
Section titled “For Users: Manual Development Session”Open a terminal and run the dev server normally:
cd ~/internal/learn/sitenpx astro devThe server starts on http://localhost:4321/. Files are watched for changes — edits to Markdown files refresh instantly in the browser.
Press Ctrl+C to stop.
Need remote access? Add --host to expose on the local network:
npx astro dev --hostThis binds to all interfaces. Check the output for the IP addresses (e.g. http://192.168.0.5:4321/).
For Agents: Background Task (Persistent)
Section titled “For Agents: Background Task (Persistent)”Agents (AI coding tools like Cline, Hermes, Little-Coder) execute commands in isolated shells that close after execution. A normal npx astro dev & will be killed when the shell exits.
The server must be a detached background task:
cd ~/internal/learn/site
# Kill any existing instancepkill -f "astro dev" 2>/dev/nullsleep 1
# Start as a detached background task with log output(npx astro dev --host > /tmp/astro-dev.log 2>&1) &disown
# Wait for it to startsleep 8
# Verify it's runningcurl -s -o /dev/null -w "%{http_code}" http://localhost:4321# Expected: 200Why the Subshell + disown Pattern?
Section titled “Why the Subshell + disown Pattern?”| Pattern | Problem |
|---|---|
npx astro dev & |
Shell job control sends SIGTERM on exit |
nohup npx astro dev & |
Leaves nohup.out in cwd; sometimes fails in subshells |
(npx astro dev > /tmp/astro-dev.log 2>&1) & disown |
Correct: subshell isolates from parent, disown removes from job table, stdout/stderr logged |
Checking the Server (Agent)
Section titled “Checking the Server (Agent)”# Check if it's still aliveps aux | grep astro | grep -v grep
# Check logstail -f /tmp/astro-dev.log
# Quick health checkcurl -s -o /dev/null -w "%{http_code}" http://localhost:4321Testing Multiple Pages (Agent)
Section titled “Testing Multiple Pages (Agent)”The Astro dev server is sensitive to rapid concurrent requests. When verifying pages, space them with delays:
for page in "/learnings/foo" "/blog/bar" "/cheatsheets/baz"; do status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:4321$page") echo " $page -> $status" sleep 0.5 # critical: prevent connection-reset from overloadingdoneContent Collection Gotcha: support/ Directories
Section titled “Content Collection Gotcha: support/ Directories”Starlight’s docsLoader() loads all *.md files under src/content/docs/ via glob. Any non-content directory (scripts, fixtures, test data) placed inside will cause schema validation errors:
[InvalidContentEntryDataError] docs → learnings/support/file.md title: RequiredFix: Move support artifacts outside the content directory entirely:
site/src/content/docs/learnings/ # only .md content filessite/learnings-support/ # scripts, fixtures, test dataDo not rely on _ prefix — the glob pattern **/[^_]*.{ext} matches filenames, not directory names, so _support/file.md still gets picked up.
Common Errors
Section titled “Common Errors”| Error | Cause | Fix |
|---|---|---|
000 status on curl (agent) |
Server crashed from concurrent requests | Add sleep 0.5 between requests |
InvalidContentEntryDataError |
Non-MD files in content dir | Move to learnings-support/ |
i18n directory does not exist |
Missing src/content/i18n/ |
Create it or ignore (non-fatal warning) |
| Blog list page 404 | page undefined in [...page] route |
See “Known Issues” section above |
Image Optimization in Astro 7.x
Section titled “Image Optimization in Astro 7.x”For blog posts with images, Astro 7.x provides built-in image optimization through the astro:assets module.
Requirements
Section titled “Requirements”- Use
.mdxfiles: Use.mdxfiles (not.md) for JSX components like<Image /> - Images in
src/directory: Astro’s image optimization requires images insrc/assets/..., notpublic/assets/... sharppackage required: Must be installed as dev dependency:pnpm add -D sharp- MDX comment syntax: Use
{/* comment */}instead of<!-- comment -->in MDX files - No top-level
await: Cannot usegetImage()with top-levelawaitin MDX files; use<Image src={imageImport} />instead
Implementation Example
Section titled “Implementation Example”---title: "Blog Post Title"date: 2026-07-06---
import { Image } from 'astro:assets';import natureImage from '../../../assets/images/image-generation/1-nature-landscape.png';
# Blog Post Content
<Image src={natureImage} alt="Nature Landscape" loading="lazy" />Image Optimization Results
Section titled “Image Optimization Results”Original PNG files (559-677kB) are optimized to WebP format (26-50kB), achieving 85-95% size reduction:
| Original | Optimized WebP | Reduction |
|---|---|---|
| 1-nature-landscape.png (580kB) | 1-nature-landscape.51SGon9e_2putX.webp (34kB) | 94% |
| 2-scifi-cyberpunk.png (631kB) | 2-scifi-cyberpunk.JjhCW2vR_Z1taUln.webp (49kB) | 92% |
| 3-portrait-realistic.png (588kB) | 3-portrait-realistic.BWz-0tfI_m5CB4.webp (26kB) | 96% |
| 4-abstract-artistic.png (677kB) | 4-abstract-artistic.Cgf-1GlJ_1ATgsX.webp (50kB) | 93% |
| 5-food-culinary.png (559kB) | 5-food-culinary.BWr7H010_Z20apFE.webp (30kB) | 95% |
Generated HTML Output
Section titled “Generated HTML Output”The build generates optimized <img> tags with WebP images:
<img src="/_astro/1-nature-landscape.51SGon9e_2putX.webp" alt="Nature Landscape" loading="lazy" decoding="async" width="512" height="512">