Astro Starlight on GitHub Pages
A project recipe for a documentation site built with Astro Starlight, deployed to GitHub Pages via GitHub Actions, with considerations for private repositories. Use this as a blueprint when setting up internal docs, product documentation, or team knowledge bases where the source repository may be private.
Project Overview
This recipe targets documentation sites for internal teams, product libraries, or knowledge bases. The key characteristic is that the source repository may be private — proprietary product docs, internal runbooks, team onboarding guides — while the built site is deployed to GitHub Pages.
| Decision | Choice |
|---|---|
| Rendering | Static site generation (SSG) |
| Hosting | GitHub Pages |
| Language | TypeScript (config) / Markdown + MDX (content) |
| Framework | Astro + Starlight |
| Search | Pagefind (build-time, zero-config) |
| CI/CD | GitHub Actions |
| Access control | GitHub repo visibility + GitHub plan tier |
Tech Stack
Core
| Library | Role |
|---|---|
| Astro | Web framework (SSG) |
| TypeScript | Type-safe configuration |
| Vite | Build tool (used by Astro internally) |
Documentation
| Library | Role |
|---|---|
| Astro Starlight | Documentation framework |
| Pagefind | Build-time full-text search |
| Expressive Code | Syntax highlighting and code blocks |
All core choices align with the Recommended Tech Stack. See individual pages for rationale and alternatives.
Architecture Overview
The architecture is straightforward. Authors write Markdown or MDX files, push to the repository, and GitHub Actions builds the site with Astro. The output is deployed as static HTML to GitHub Pages. There is no backend, no database, and no client-side JavaScript beyond what Starlight includes by default (search index, theme toggle).
Authors commit content changes to the repository. On every push to main, GitHub Actions checks out the code, runs the Astro build, and deploys the resulting static files to GitHub Pages. Readers access the site through a browser — no authentication is involved unless the GitHub plan supports private Pages visibility.
Content Structure
src/
├── content/
│ └── docs/
│ ├── getting-started.md
│ ├── guides/
│ │ ├── installation.md
│ │ └── configuration.md
│ └── reference/
│ └── api.md
├── assets/
│ └── logo.svg
└── content.config.ts
astro.config.mjs
package.json
Starlight generates the sidebar automatically from the filesystem. Ordering is controlled via the sidebar configuration in astro.config.mjs or frontmatter in each file. Content goes in src/content/docs/.
Key Features Out of the Box
- Auto-generated sidebar from filesystem structure
- Pagefind search — full-text, zero-config, runs entirely at build time
- Expressive Code — file titles, line highlighting, diff markers, terminal frames
- Built-in components —
<Aside>,<Card>,<CardGrid>,<Tabs>,<Steps>,<LinkCard> - Dark / light mode — included in default theme
- i18n support — built-in if multi-language docs are needed later
Pagefind search works entirely at build time — no external search service, no API keys, no data leaving your infrastructure. This makes Starlight particularly well-suited for internal or confidential documentation.
GitHub Pages & Private Repos
Plan Requirements
GitHub Pages is available for private repos on paid plans, but the access model varies by plan tier.
| GitHub Plan | Pages on Private Repos | Site Visibility |
|---|---|---|
| Free | ❌ Public repos only | Public |
| Pro (personal) | ✅ | Public |
| Team | ✅ | Public (cannot restrict) |
| Enterprise Cloud | ✅ | Public or private (configurable) |
On the Team plan, a GitHub Pages site built from a private repo is publicly accessible on the internet. The repo is private, but the deployed site is not. Only GitHub Enterprise Cloud offers a toggle to restrict Pages site visibility to organization members. If your documentation contains confidential information and you're on a Team plan, consider alternative hosting with access control — for example, Cloud Run with Identity-Aware Proxy or Cloudflare Access.
Repository Configuration
- Go to repo Settings → Pages
- Under Source, select GitHub Actions
- No branch selection needed — the workflow handles everything
Do not select "Deploy from a branch." The Astro build produces output that must be uploaded as an artifact. The GitHub Actions source is required for the workflow described below.
Deployment Overview
Astro Configuration
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
site: 'https://your-org.github.io',
// Set base only for project pages (not org pages or custom domains)
// base: '/repo-name/',
integrations: [
starlight({
title: 'My Docs',
sidebar: [
{ label: 'Guides', autogenerate: { directory: 'guides' } },
{ label: 'Reference', autogenerate: { directory: 'reference' } },
],
}),
],
});
site is always required — Astro uses it to generate canonical URLs and sitemap entries. Set base only if the site is hosted at a subpath (e.g., https://org.github.io/repo-name/). For organization-level pages or custom domains, omit base entirely.
GitHub Actions Workflow
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
The workflow triggers on pushes to main and can be run manually via workflow_dispatch. Permissions are scoped per job: build only needs contents: read to check out code, while deploy needs pages: write and id-token: write for the OIDC token that authenticates with GitHub Pages. The concurrency group prevents overlapping deployments. The build job checks out code, installs dependencies, builds the Astro site, and uploads dist/ as a Pages artifact. The deploy job deploys the artifact and links the deployment to the github-pages environment.
Astro outputs to dist/ by default. If you change the output directory in astro.config.mjs, update the path in the upload artifact step to match.
Custom Domain
To use a custom domain, create a CNAME file in the public/ directory containing the domain name. Astro copies everything in public/ to the build output root, so the file ends up at the right location for GitHub Pages.
docs.example.com
Configure DNS with your domain registrar: for a subdomain like docs.example.com, create a CNAME record pointing to your-org.github.io. For an apex domain, create A records pointing to GitHub's IPs (see the GitHub Pages custom domain docs). When using a custom domain, remove the base setting from astro.config.mjs — the site is served from the domain root.
Place the CNAME file in public/, not in the repository root. Files in the repo root are not included in Astro's build output. If the CNAME file is missing from the deployed site, GitHub Pages removes the custom domain configuration on each deployment.
Common Pitfalls
- Base path misconfiguration — Setting
basewhen it's not needed (or omitting it when it is) breaks all asset URLs, stylesheets, and navigation links. If the site shows unstyled HTML, checkbasefirst. - Wrong Pages source — Selecting "Deploy from a branch" instead of "GitHub Actions" causes deployments to fail silently. The workflow uploads an artifact; it does not push to a branch.
- Missing CNAME file — If
public/CNAMEis missing, each deployment resets the custom domain in GitHub Pages settings. The site reverts to*.github.iountil manually reconfigured. - Permission errors — The workflow requires both
pages: writeandid-token: write. Missing either causes a "resource not accessible by integration" error. - Stale deployments — GitHub Pages uses a CDN. After deployment, it can take a few minutes for changes to appear. Hard-refresh or use a private/incognito window to verify.
Task Breakdown
| Epic | Description | Ballpark (dev-days) |
|---|---|---|
| Project Setup | Scaffold Starlight project, configure TypeScript, set up linting and formatting | 0.5–1 |
| Site Configuration | Configure astro.config.mjs (site URL, sidebar, navigation, branding) | 0.5–1 |
| CI/CD & Deployment | GitHub Actions workflow, GitHub Pages configuration, custom domain (if applicable) | 0.5–1 |
| Content Structure | Create directory layout, set up content categories, define information architecture | 1–2 |
| Initial Content | Write first batch of documentation pages (estimate 0.25–0.5 days per page) | 3–10 |
| Customization | Custom components, theme adjustments, logo and branding, custom CSS | 1–3 |
| Review & Polish | Content review, link checking, cross-browser testing, search verification | 1–2 |
Ballpark Totals
| Metric | Range |
|---|---|
| Total effort (excluding content writing) | 4–10 dev-days |
| Total effort (including ~20 pages of content) | 8–20 dev-days |
| Duration (1 developer) | 1–4 weeks |
Content writing dominates the effort. The infrastructure — scaffolding, CI/CD, deployment — can be done in a single day. Duration depends almost entirely on how many pages need to be written and how technical the content is. Apply complexity multipliers for i18n, custom component development, or migration from an existing docs platform. Always present estimates as ranges.
What's Not Included
- Content writing beyond initial pages (ongoing documentation is a continuous effort)
- UX/UI design for custom themes
- Internationalization — add +10–20% if needed
- Migration from an existing documentation platform (Confluence, Notion, etc.)
- Custom search infrastructure (Pagefind covers most needs; add 1–2 days if Algolia or similar is required)
- Project management overhead — typically +20–30% (see Common Pitfalls)
Further Reading
Internal docs:
- Astro — Astro framework overview
- Astro Starlight — Starlight documentation framework
- Vite — build tool powering Astro
- Estimation — techniques and complexity factors
- Requirement Engineering — project requirements checklist
- Deploy — other hosting options
- Recommended Tech Stack — full stack overview
External resources: