Starlight Project Structure and Sidebar Navigation

A practical tutorial for understanding how Astro Starlight projects are organized and how to build clear sidebar navigation for documentation, lessons, and world bible sites.

What You Are Learning

This tutorial focuses on two important parts of an Astro Starlight project:

These two topics matter because Starlight sites are usually content-heavy. Once you have many lesson pages, worldbuilding pages, character files, reference notes, or technical guides, structure and navigation become the difference between a useful site and a confusing pile of pages.

The Big Picture

Starlight is an Astro integration for documentation-style websites. Astro handles the site build system, routing, assets, and page rendering. Starlight adds documentation features such as a sidebar, search, page layout, table of contents, and Markdown/MDX-friendly authoring.

Astro project
  ↓
Starlight integration
  ↓
Markdown and MDX documentation pages
  ↓
Sidebar, search, page layout, and static site output

For most projects, your everyday work will happen in these places:

src/content/docs/     documentation pages
src/components/       reusable components
src/assets/           source-managed images and assets
public/               static files copied directly to the final site
astro.config.mjs      main Astro and Starlight configuration

Starting Point: Create a Starlight Project

The common setup command is:

npm create astro@latest

During setup, choose a documentation/Starlight starter if offered. Another common approach is to create an Astro project first, then add Starlight:

npx astro add starlight

Then run the development server:

npm run dev

Build the production site with:

npm run build

The finished static site is usually generated into:

dist/

Typical Starlight Project Structure

A small Starlight project may look like this:

my-starlight-site/
  public/
    favicon.svg
  src/
    assets/
    content/
      docs/
        index.md
        getting-started.md
    components/
  astro.config.mjs
  package.json
  tsconfig.json

A larger project might look like this:

my-starlight-site/
  public/
    favicon.png
    images/
      maps/
      diagrams/
  src/
    assets/
      logo.svg
    components/
      CharacterCard.astro
      InfoBox.astro
      LessonObjectives.astro
    content/
      docs/
        index.md
        getting-started.md
        worldbuilding/
          index.md
          regions/
            europe.md
            austral-confluence.md
          characters/
            character-template.md
            example-character.md
        lessons/
          index.md
          markdown-basics.md
          mdx-basics.mdx
        reference/
          yaml.md
          deployment.md
    styles/
      custom.css
  astro.config.mjs
  package.json
  tsconfig.json

The main idea is simple: content goes in src/content/docs/. The folder structure inside docs often becomes your site structure and sidebar structure.

The public Folder

The public/ folder is for static files that should be copied directly to the final website without being processed by Astro.

public/
  favicon.png
  images/
    map.png
    character-portrait.png
  downloads/
    world-bible-template.pdf

Files in public/ are referenced from the site root.

![World Map](/images/map.png)

Use public/ for simple static assets such as favicons, downloadable files, screenshots, and images you want to reference by direct path.

The src/assets Folder

The src/assets/ folder is for assets managed by Astro's build pipeline. This is often useful for logos, imported images, or files used directly by components.

src/
  assets/
    logo.svg
    hero-image.png

For beginner documentation sites, you can often start with public/. As the site grows, src/assets/ becomes more useful for optimized or component-driven assets.

The src/content/docs Folder

This is the heart of a Starlight site. Documentation pages live in:

src/content/docs/

Example:

src/content/docs/index.md
src/content/docs/getting-started.md
src/content/docs/lessons/markdown-basics.md
src/content/docs/worldbuilding/character-template.md

Each Markdown or MDX file becomes a page in the docs site.

src/content/docs/index.md
  → /

src/content/docs/getting-started.md
  → /getting-started/

src/content/docs/lessons/markdown-basics.md
  → /lessons/markdown-basics/

src/content/docs/worldbuilding/character-template.md
  → /worldbuilding/character-template/

Markdown and MDX Files

Most pages can be plain Markdown:

example-page.md

Use MDX when the page needs components:

interactive-example.mdx

Markdown is best for normal writing. MDX is best for pages that need custom cards, stat blocks, callouts, tabs, visual components, or interactive examples.

Basic Page Frontmatter

Every Starlight page usually begins with frontmatter. Frontmatter is YAML metadata at the top of a Markdown or MDX file.

---
title: "Getting Started"
description: "Learn how this documentation site is organized."
---

# Getting Started

This page introduces the project.

The title is especially important because Starlight can use it for page headings, browser metadata, and sidebar labels.

The astro.config.mjs File

The main Starlight configuration lives in astro.config.mjs.

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Documentation Site',
    }),
  ],
});

This is where you configure the site title, logo, sidebar, social links, custom CSS, table of contents behavior, plugins, and other Starlight options.

Adding Custom CSS

For simple customization, create a CSS file:

src/styles/custom.css

Then register it in astro.config.mjs:

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Documentation Site',
      customCss: ['./src/styles/custom.css'],
    }),
  ],
});

This keeps custom styling separate from your Markdown content.

How Starlight Sidebar Navigation Works

Starlight can build sidebar navigation in two main ways:

For small or early projects, autogenerated navigation is often enough. For larger lesson libraries, world bibles, or professional docs, manual navigation gives more control.

Autogenerated Sidebar

By default, Starlight can generate the sidebar based on files and folders in src/content/docs/. For example:

src/content/docs/
  index.md
  getting-started.md
  lessons/
    markdown-basics.md
    mdx-basics.md
  worldbuilding/
    character-template.md
    region-template.md

This can create a sidebar similar to:

Getting Started
Lessons
  Markdown Basics
  MDX Basics
Worldbuilding
  Character Template
  Region Template

The advantage is speed. You add files and Starlight finds them.

The disadvantage is that folder names, file names, and page titles need to be carefully managed or the sidebar can become messy.

Manual Sidebar

Manual sidebar navigation is configured in astro.config.mjs.

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My Documentation Site',
      sidebar: [
        {
          label: 'Start Here',
          items: [
            { label: 'Introduction', slug: 'intro' },
            { label: 'Getting Started', slug: 'getting-started' },
          ],
        },
        {
          label: 'Lessons',
          items: [
            { label: 'Markdown Basics', slug: 'lessons/markdown-basics' },
            { label: 'MDX Basics', slug: 'lessons/mdx-basics' },
          ],
        },
      ],
    }),
  ],
});

The label is what appears in the sidebar. The slug points to the page route.

Slug Basics

A slug is the URL path to a page without the leading slash.

src/content/docs/getting-started.md
  slug: 'getting-started'

src/content/docs/lessons/markdown-basics.md
  slug: 'lessons/markdown-basics'

src/content/docs/worldbuilding/characters/example-character.md
  slug: 'worldbuilding/characters/example-character'

If a sidebar item points to the wrong slug, the link will be broken.

Sidebar Groups

A sidebar group collects related pages under a heading.

sidebar: [
  {
    label: 'Worldbuilding',
    items: [
      { label: 'World Bible Overview', slug: 'worldbuilding/overview' },
      { label: 'Character Template', slug: 'worldbuilding/character-template' },
      { label: 'Region Template', slug: 'worldbuilding/region-template' },
    ],
  },
]

For lesson sites, groups could be courses or difficulty levels.

Beginner Lessons
Intermediate Lessons
Advanced Lessons
Reference

For worldbuilding sites, groups could be content categories.

World Overview
Regions
Characters
Factions
Locations
Storylines
Timeline
Reference

Nested Sidebar Groups

For larger sites, groups can be nested.

sidebar: [
  {
    label: 'Worldbuilding',
    items: [
      {
        label: 'Regions',
        items: [
          { label: 'Europe', slug: 'worldbuilding/regions/europe' },
          { label: 'Austral Confluence', slug: 'worldbuilding/regions/austral-confluence' },
        ],
      },
      {
        label: 'Characters',
        items: [
          { label: 'Character Template', slug: 'worldbuilding/characters/template' },
          { label: 'Example Character', slug: 'worldbuilding/characters/example-character' },
        ],
      },
    ],
  },
]

Nested groups are powerful, but too many levels can make the sidebar harder to use. Two levels is usually comfortable. Three levels should be used carefully.

Autogenerated Groups Inside Manual Sidebar

A useful middle path is to define the major groups manually, but let Starlight autogenerate the pages inside a folder.

sidebar: [
  {
    label: 'Lessons',
    autogenerate: { directory: 'lessons' },
  },
  {
    label: 'Worldbuilding',
    autogenerate: { directory: 'worldbuilding' },
  },
]

This gives you control over the big categories while avoiding the need to manually list every page.

Recommended Structure for a Lesson Site

For a lesson library, use folders that match how a learner thinks.

src/content/docs/
  index.md
  lessons/
    index.md
    beginner/
      html-basics.md
      css-basics.md
      javascript-basics.md
    intermediate/
      markdown-mdx.md
      astro-components.md
      starlight-sidebar.md
    advanced/
      content-collections.md
      custom-components.mdx
      deployment-workflow.md
  reference/
    glossary.md
    commands.md
    troubleshooting.md

Possible sidebar:

sidebar: [
  {
    label: 'Start Here',
    items: [
      { label: 'Home', slug: '' },
      { label: 'How to Use This Site', slug: 'lessons' },
    ],
  },
  {
    label: 'Beginner Lessons',
    autogenerate: { directory: 'lessons/beginner' },
  },
  {
    label: 'Intermediate Lessons',
    autogenerate: { directory: 'lessons/intermediate' },
  },
  {
    label: 'Advanced Lessons',
    autogenerate: { directory: 'lessons/advanced' },
  },
  {
    label: 'Reference',
    autogenerate: { directory: 'reference' },
  },
]

Recommended Structure for a World Bible Site

For a world bible, use folders that match the types of entries you will create again and again.

src/content/docs/
  index.md
  world/
    overview.md
    timeline.md
    technology.md
  regions/
    index.md
    europe.md
    austral-confluence.md
    atlantic-compact.md
  characters/
    index.md
    character-template.md
    example-character.md
  factions/
    index.md
    faction-template.md
  locations/
    index.md
    location-template.md
  storylines/
    index.md
    storyline-template.md
  reference/
    glossary.md
    naming-conventions.md

Possible sidebar:

sidebar: [
  {
    label: 'World Overview',
    items: [
      { label: 'Home', slug: '' },
      { label: 'Overview', slug: 'world/overview' },
      { label: 'Timeline', slug: 'world/timeline' },
      { label: 'Technology', slug: 'world/technology' },
    ],
  },
  {
    label: 'Regions',
    autogenerate: { directory: 'regions' },
  },
  {
    label: 'Characters',
    autogenerate: { directory: 'characters' },
  },
  {
    label: 'Factions',
    autogenerate: { directory: 'factions' },
  },
  {
    label: 'Locations',
    autogenerate: { directory: 'locations' },
  },
  {
    label: 'Storylines',
    autogenerate: { directory: 'storylines' },
  },
  {
    label: 'Reference',
    autogenerate: { directory: 'reference' },
  },
]

Page Ordering

Navigation order matters. A sidebar should teach the reader where to start and what to read next.

For manual sidebars, the order is the order you write in astro.config.mjs.

items: [
  { label: 'Introduction', slug: 'intro' },
  { label: 'Installation', slug: 'installation' },
  { label: 'Project Structure', slug: 'project-structure' },
  { label: 'Sidebar Navigation', slug: 'sidebar-navigation' },
]

For autogenerated sidebars, file and folder names become more important. If you need strict ordering, manual sidebar configuration is usually clearer.

Index Pages

Each major folder should usually have an index.md page.

src/content/docs/lessons/index.md
src/content/docs/worldbuilding/index.md
src/content/docs/characters/index.md

An index page acts like a section landing page. It can explain what the section contains and link to important pages.

---
title: "Characters"
description: "Character profiles, character templates, and major figures."
---

# Characters

This section contains character profiles and reusable templates.

## Start Here

- [Character Template](/characters/character-template/)
- [Example Character](/characters/example-character/)

Good Sidebar Labels

Good sidebar labels are short, clear, and predictable.

Weak Label Better Label
Stuff Reference
People Things Characters
Places and Such Locations
How It All Works Maybe System Rules
Misc Notes Glossary

Manual vs Autogenerated Sidebar

Approach Best For Tradeoff
Autogenerated Small sites, quick starts, simple folder structures Less precise control
Manual Polished docs, lesson paths, curated world bibles More maintenance
Hybrid Growing sites with large categories Requires thoughtful folder structure

For most serious projects, the hybrid approach is the best long-term choice.

Hybrid Sidebar Pattern

This pattern works well when you want major categories in a deliberate order but do not want to manually list every page.

sidebar: [
  {
    label: 'Start Here',
    items: [
      { label: 'Introduction', slug: '' },
      { label: 'How to Use This Site', slug: 'getting-started' },
    ],
  },
  {
    label: 'Lessons',
    autogenerate: { directory: 'lessons' },
  },
  {
    label: 'World Bible',
    autogenerate: { directory: 'worldbuilding' },
  },
  {
    label: 'Reference',
    autogenerate: { directory: 'reference' },
  },
]

This is usually easier to maintain than a fully manual sidebar.

Example: Complete astro.config.mjs

Here is a practical example for a combined lesson and world bible site:

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';

export default defineConfig({
  site: 'https://example.com',
  integrations: [
    starlight({
      title: 'World Bible and Lessons',
      customCss: ['./src/styles/custom.css'],
      sidebar: [
        {
          label: 'Start Here',
          items: [
            { label: 'Home', slug: '' },
            { label: 'Getting Started', slug: 'getting-started' },
          ],
        },
        {
          label: 'Lessons',
          autogenerate: { directory: 'lessons' },
        },
        {
          label: 'World Bible',
          items: [
            { label: 'Overview', slug: 'world/overview' },
            { label: 'Timeline', slug: 'world/timeline' },
            {
              label: 'Reference Sections',
              items: [
                { label: 'Regions', slug: 'regions' },
                { label: 'Characters', slug: 'characters' },
                { label: 'Factions', slug: 'factions' },
                { label: 'Locations', slug: 'locations' },
              ],
            },
          ],
        },
        {
          label: 'Reference',
          autogenerate: { directory: 'reference' },
        },
      ],
    }),
  ],
});

Common Sidebar Mistakes

Broken slugs

A sidebar item must point to an existing page.

Bad:
{ label: 'Markdown Basics', slug: 'markdown-basics' }

If the real file is:
src/content/docs/lessons/markdown-basics.md

Better:
{ label: 'Markdown Basics', slug: 'lessons/markdown-basics' }

Too many top-level groups

If everything is top-level, nothing feels organized. Group related pages together.

Too much nesting

If a reader has to open four levels of navigation to find a page, the site is probably too deeply nested.

Vague labels

Labels should tell the reader exactly what section they are entering.

Common Project Structure Mistakes

Putting docs pages in the wrong folder

Wrong:
src/pages/lesson-one.md

Usually correct for Starlight docs:
src/content/docs/lesson-one.md

Mixing unrelated content in one folder

Messy:
src/content/docs/
  europe.md
  markdown-basics.md
  veritas.md
  css-basics.md
  glossary.md

Better:
src/content/docs/
  regions/europe.md
  lessons/markdown-basics.md
  characters/veritas.md
  lessons/css-basics.md
  reference/glossary.md

Skipping index pages

Folders without index pages can feel like drawers without labels. Add a section landing page for each major folder.

Practical Build Plan

When starting a new Starlight site, build in this order:

  1. Create the project.
  2. Add or confirm Starlight.
  3. Create the major folders under src/content/docs/.
  4. Add index.md pages for each major section.
  5. Add a few sample pages.
  6. Use autogenerated sidebar first.
  7. Switch to manual or hybrid sidebar when the structure becomes clear.
  8. Add custom CSS only after the content structure works.
  9. Run npm run build to catch broken links or configuration problems.

Practice Exercise: Create a Lesson Section

Create this folder structure:

src/content/docs/
  lessons/
    index.md
    markdown-basics.md
    mdx-basics.md

Create lessons/index.md:

---
title: "Lessons"
description: "Tutorials and learning paths."
---

# Lessons

This section contains tutorials and learning guides.

## Start Here

- [Markdown Basics](/lessons/markdown-basics/)
- [MDX Basics](/lessons/mdx-basics/)

Add this sidebar group:

{
  label: 'Lessons',
  autogenerate: { directory: 'lessons' },
}

Practice Exercise: Create a World Bible Section

Create this folder structure:

src/content/docs/
  world/
    overview.md
    timeline.md
  characters/
    index.md
    character-template.md
  regions/
    index.md
    region-template.md

Add this sidebar configuration:

sidebar: [
  {
    label: 'World',
    items: [
      { label: 'Overview', slug: 'world/overview' },
      { label: 'Timeline', slug: 'world/timeline' },
    ],
  },
  {
    label: 'Characters',
    autogenerate: { directory: 'characters' },
  },
  {
    label: 'Regions',
    autogenerate: { directory: 'regions' },
  },
]

Troubleshooting

The page exists but does not appear in the sidebar

Check whether you are using a manual sidebar. If the sidebar is manual, Starlight will not automatically show every new page unless you add it or use an autogenerated group.

The sidebar link goes to a 404 page

Check the slug. The slug should match the route created by the file path under src/content/docs/.

The sidebar order is wrong

Use a manual sidebar for strict order. Autogenerated sidebars are convenient, but manual sidebars are better for carefully designed reading paths.

The site builds locally but assets are missing

Check whether the files are in public/ and referenced with root paths like /images/example.png.

Recommended Naming Conventions

Pick one naming style and stay consistent.

Good:
markdown-basics.md
character-template.md
world-bible-overview.md

Also acceptable:
markdown_basics.md
character_template.md
world_bible_overview.md

Avoid:
Markdown Basics FINAL New.md
character template copy 2.md

For web routes, hyphenated names are common because they produce readable URLs.

Cheat Sheet

Thing Where It Usually Goes
Documentation page src/content/docs/
Markdown page src/content/docs/example.md
MDX page src/content/docs/example.mdx
Reusable component src/components/
Custom CSS src/styles/custom.css
Static images/downloads public/
Main Starlight config astro.config.mjs
Production output dist/

Simple Rule of Thumb

Use folders to organize meaning.
Use frontmatter to describe pages.
Use the sidebar to guide readers.
Use manual navigation when order matters.
Use autogenerated navigation when volume matters.
Use index pages to explain each section.

What to Learn Next