What This Tutorial Covers
This tutorial assumes you already know the basic Astro and Starlight workflow:
npm create astro@latest
npx astro add starlight
npm run dev
npm run build
Now the goal is to move beyond a simple docs site and learn how to organize a serious project with reusable structure, content strategy, custom components, deployment settings, and troubleshooting habits.
The Big Picture
Astro is useful when your site is mostly content, but you still want modern tooling. Starlight is a documentation framework built on Astro. Together, they are a strong choice for:
- Documentation sites
- Lesson libraries
- Software manuals
- Worldbuilding encyclopedias
- Reference guides
- Technical tutorials
- Course notes
The mental model is simple:
Markdown or MDX files = content
Astro components = reusable page pieces
Starlight config = docs structure and navigation
Astro build = final static website
Recommended Project Structure
A serious Starlight site should be organized intentionally. A common structure looks like this:
my-starlight-site/
astro.config.mjs
package.json
public/
favicon.svg
images/
src/
assets/
components/
CalloutBox.astro
LessonCard.astro
CharacterCard.astro
TimelineList.astro
content/
docs/
index.md
getting-started.md
lessons/
reference/
worldbuilding/
styles/
custom.css
Starlight expects most documentation pages to live inside:
src/content/docs/
That folder becomes the backbone of the site. The file and folder names inside it help determine page URLs and sidebar structure.
Configuring Starlight in astro.config.mjs
The main Starlight configuration usually lives inside astro.config.mjs. This is where you control the site title, description, sidebar, social links, plugins, custom CSS, and other global settings.
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
integrations: [
starlight({
title: 'My Knowledge Site',
description: 'Lessons, references, and project notes.',
sidebar: [
{
label: 'Start Here',
items: [
{ label: 'Introduction', slug: 'intro' },
{ label: 'Project Setup', slug: 'project-setup' }
]
},
{
label: 'Lessons',
autogenerate: { directory: 'lessons' }
},
{
label: 'Reference',
autogenerate: { directory: 'reference' }
}
],
customCss: ['./src/styles/custom.css']
})
]
});
For a small site, manual sidebar links are fine. For a larger site, autogenerated sidebar sections save time and reduce broken navigation.
Sidebar Strategy
Intermediate and advanced Starlight projects need a sidebar strategy. Do not let the sidebar become a junk drawer.
A good sidebar usually has a few clear groups:
Start Here
Lessons
Guides
Reference
Examples
Appendix
For a worldbuilding site, the groups might be:
World Overview
Regions
Characters
Factions
Locations
Storylines
Timeline
Reference
For a course or lesson site, the groups might be:
Course Introduction
Core Lessons
Practice Projects
Reference Sheets
Troubleshooting
Next Steps
Using Frontmatter Well
Markdown pages in Starlight use frontmatter at the top of the file. Frontmatter is metadata about the page.
---
title: "Working with Astro Components"
description: "Learn how reusable Astro components improve a Starlight site."
sidebar:
label: "Astro Components"
order: 3
---
# Working with Astro Components
Page content goes here.
Useful frontmatter can include:
title: the page titledescription: the search/SEO descriptionsidebar.label: a shorter sidebar titlesidebar.order: the page order inside a sidebar groupdraft: useful in some workflows for unfinished content
Markdown vs MDX
Use regular Markdown for most pages. Use MDX when a page needs interactive or reusable components.
| Use Markdown When... | Use MDX When... |
|---|---|
| The page is mostly text, headings, lists, and code blocks. | The page needs Astro, React, Vue, Svelte, or custom components. |
| You want simple authoring. | You want reusable visual cards, tabs, maps, lesson widgets, or diagrams. |
| The page is a reference article. | The page behaves like a mini application or enhanced lesson. |
Example MDX usage:
---
title: "Lesson with a Custom Card"
---
import LessonCard from '../../components/LessonCard.astro';
# Lesson with a Custom Card
<LessonCard title="Practice Project" level="Intermediate" />
Creating Reusable Astro Components
Reusable components are one of the main reasons to move beyond hand-coded HTML. They keep repeated content consistent.
Example component:
---
const { title, level, description } = Astro.props;
---
<article class="lesson-card">
<h3>{title}</h3>
<p><strong>Level:</strong> {level}</p>
<p>{description}</p>
</article>
Then use it in an MDX file:
import LessonCard from '../../components/LessonCard.astro';
<LessonCard
title="Deploying a Starlight Site"
level="Intermediate"
description="Learn how build output, routes, and hosting settings work."
/>
Custom CSS Without Fighting Starlight
Starlight already provides a strong visual foundation. Instead of replacing everything, start with small custom improvements.
In astro.config.mjs:
starlight({
title: 'My Docs',
customCss: ['./src/styles/custom.css']
})
Then create:
src/styles/custom.css
Example:
.lesson-card {
border: 1px solid var(--sl-color-gray-5);
border-radius: 0.75rem;
padding: 1rem;
margin: 1rem 0;
}
.lesson-card h3 {
margin-top: 0;
}
Best practice: add custom styles for your own classes first. Avoid deeply overriding Starlight internals unless you have a specific reason.
Content Collections and Structured Content
Astro content collections help manage structured content with schemas and type safety. Starlight already uses a docs collection, but you can also create additional collections for data-like content.
For example, a lesson collection could describe lessons with required metadata:
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
const lessons = defineCollection({
schema: z.object({
title: z.string(),
level: z.enum(['beginner', 'intermediate', 'advanced']),
order: z.number(),
topics: z.array(z.string()).optional()
})
});
export const collections = { lessons };
This is useful when you want Astro to validate your content. For example, if every lesson must have a level, the schema can enforce that.
Advanced Pattern: Index Pages Generated from Content
Instead of manually maintaining a list of lessons, you can generate an index page from a collection.
---
import { getCollection } from 'astro:content';
const lessons = await getCollection('lessons');
const sortedLessons = lessons.sort((a, b) => a.data.order - b.data.order);
---
<h1>Lesson Index</h1>
<ul>
{sortedLessons.map((lesson) => (
<li>
<a href={`/lessons/${lesson.id}/`}>{lesson.data.title}</a>
<span> - {lesson.data.level}</span>
</li>
))}
</ul>
This pattern is powerful for lesson libraries, character indexes, reference pages, bestiaries, timelines, and project archives.
Advanced Pattern: A Worldbuilding Index
For a worldbuilding site, you could create structured collections for characters, locations, factions, or storylines.
const characters = defineCollection({
schema: z.object({
title: z.string(),
region: z.string(),
faction: z.string().optional(),
role: z.string(),
status: z.enum(['active', 'missing', 'dead', 'unknown']).optional()
})
});
Then each character file has consistent metadata:
---
title: "Example Character"
region: "Europe"
faction: "House Example"
role: "Diplomat"
status: "active"
---
## Identity
## Background
## Relationships
## Story Use
This lets the site generate character lists, region indexes, faction pages, and cross-reference pages.
Using Built-In Starlight Features
Starlight gives you many features without requiring you to build them manually:
- Sidebar navigation
- Search
- Responsive layout
- Accessible typography
- Code highlighting
- Dark mode
- SEO-friendly pages
- Markdown, MDX, and Markdoc support
Before building your own version of a feature, check whether Starlight already provides it.
Adding Diagrams
For lessons and worldbuilding, diagrams are often helpful. You can use Mermaid, SVG, or custom Astro components.
For Mermaid, one approach is to create a component that safely renders Mermaid blocks. A simple component might look like this:
---
const { chart } = Astro.props;
---
<pre class="mermaid">{chart}</pre>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
For production, consider loading Mermaid once globally instead of importing it on every page.
Adding React or Other Interactive Components
Astro lets you use interactive components only when needed. This is one of its biggest advantages.
Example use cases:
- Search filters
- Character sorters
- Interactive timelines
- Quiz widgets
- Code demo toggles
- Dice rollers
Example hydration pattern:
<CharacterFilter client:load />
Common hydration directives include:
client:load: load immediately in the browserclient:idle: load when the browser is idleclient:visible: load when the component enters the viewportclient:only: render only on the client
Use the lightest option that solves the problem. A static page does not need a hydrated component.
Intermediate Deployment Knowledge
For a static Starlight site, the normal build command is:
npm run build
The default output folder is usually:
dist
Common host settings:
| Host | Build Command | Publish / Output Directory |
|---|---|---|
| Netlify | npm run build |
dist |
| Vercel | npm run build |
dist |
| Cloudflare Pages | npm run build |
dist |
| GitHub Pages | GitHub Actions workflow | dist |
GitHub Pages Base Path Warning
If you deploy to a GitHub Pages project URL, your site may live at a path like:
https://username.github.io/repository-name/
In that case, you may need to configure site and base in astro.config.mjs:
export default defineConfig({
site: 'https://username.github.io',
base: '/repository-name',
integrations: [starlight({ title: 'My Docs' })]
});
If the site works locally but assets break on GitHub Pages, check the base path first.
Performance Best Practices
Astro and Starlight are already performance-oriented, but larger sites still need discipline.
- Use static Markdown when possible.
- Use MDX only when components are needed.
- Hydrate interactive components only when necessary.
- Prefer
client:visibleorclient:idleoverclient:loadwhen possible. - Compress images before adding them to the site.
- Keep sidebar groups focused.
- Generate indexes from metadata instead of maintaining duplicate lists by hand.
Content Maintenance Strategy
Advanced Astro/Starlight work is not only about code. It is also about maintaining a growing content library.
Use consistent file names:
good-file-name.md
another-clear-file-name.md
not This Random File Name.md
Use consistent folder names:
lessons/
reference/
projects/
worldbuilding/
characters/
factions/
locations/
Use consistent page templates:
Overview
Concept
Example
Walkthrough
Common Mistakes
Practice
Summary
Consistency matters more as the site grows.
Common Problems and Fixes
Problem: The sidebar page order is wrong
Fix it with frontmatter:
---
title: "Advanced Components"
sidebar:
order: 5
---
Problem: A page does not appear in the sidebar
Check the file location, sidebar configuration, and whether the page is inside the expected docs directory.
Problem: MDX import fails
Check the relative path and make sure the MDX integration is installed if needed.
Problem: Deployment works but images are broken
Check whether images are in public/ or imported from src/assets/. Also check the site base path if deploying under a subdirectory.
Problem: Build works locally but fails on the host
Check Node version, lockfile consistency, missing environment variables, and case-sensitive file names.
Suggested Intermediate Practice Project
Build a Starlight site with these sections:
Start Here
Lessons
Reference
Examples
Troubleshooting
Add at least:
- Five Markdown lesson pages
- One MDX page using a custom component
- One autogenerated sidebar group
- One custom CSS file
- One generated index page
- One deployment to Vercel, Netlify, Cloudflare Pages, or GitHub Pages
Suggested Advanced Practice Project
Build a reference site with structured collections:
characters
locations
factions
lessons
references
Then create:
- A generated character index
- A generated location index
- A generated lesson index
- Reusable card components
- Filtered or grouped lists
- Custom CSS
- A clean deployment workflow
This project teaches you the real value of Astro: content is not just pages; content can become structured data that generates pages, indexes, and navigation.
Advanced Mental Model
Beginner Astro thinking:
I write pages and Astro publishes them.
Intermediate Astro thinking:
I write reusable layouts and components so pages stay consistent.
Advanced Astro thinking:
I model my content as structured data, then generate pages, indexes, navigation, and references from that data.
When Astro + Starlight Is the Right Tool
Astro + Starlight is a strong choice when the project is mostly content and reference material.
Use it for:
- Docs
- Lessons
- Guides
- Manuals
- Worldbuilding encyclopedias
- Static course sites
- Knowledge bases
Consider another framework when the project is mostly a full application:
- Large dashboard
- Logged-in user system
- Database editing app
- Real-time collaboration
- Complex admin interface
Checklist
Before calling a Starlight project maintainable, check the following:
- The sidebar is organized intentionally.
- Page filenames are predictable.
- Frontmatter is consistent.
- Repeated UI is moved into components.
- Custom CSS is isolated and minimal.
- Indexes are generated when possible.
- Images and assets are organized.
- The site builds locally with
npm run build. - The deployment host uses
distas the output directory. - The project has a clear content maintenance strategy.
Summary
Astro + Starlight starts simple, but it scales well when you treat it as a content system instead of a pile of pages. The core skills are:
- Organizing content into folders
- Using frontmatter consistently
- Configuring sidebars carefully
- Adding reusable Astro components
- Using MDX only where it helps
- Creating structured content collections
- Generating index pages from content
- Deploying with the correct build and output settings
The more your site grows, the more valuable Astro becomes. A single reusable component or schema can save dozens of future edits.