Host a Documentation Site with Astro Starlight
Starlight is a documentation theme built on Astro. It turns a folder of Markdown files into a complete documentation site: navigation sidebar, full-text search, dark mode, mobile layout, and internationalization are all built in. The output is static HTML, so hosting it requires nothing more than a static file server.
That simplicity still leaves the documentation-specific work: configuring the sidebar, getting search working, deploying the static output to Railway, and putting the site behind your own domain. This guide covers each one; for general Astro deployment patterns (SSR, Dockerfiles, one-click templates), see the Astro guide.
Create a Starlight project
You need Node.js installed. Scaffold a new project with the Starlight template:
npm create astro@latest my-docs -- --template starlightAccept the defaults when prompted, then start the dev server:
cd my-docs
npm run devOpen http://localhost:4321 to see the site. Documentation pages live in src/content/docs/ as Markdown or MDX files. Each file becomes a route: src/content/docs/guides/install.md is served at /guides/install.
Every page needs a title in its frontmatter:
---
title: Installation
description: How to install the CLI.
---
Install the CLI with npm:
...Configure the sidebar
The sidebar is defined in astro.config.mjs. You can list pages explicitly, or point a group at a directory and let Starlight generate the entries from the files it finds.
// astro.config.mjs
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
export default defineConfig({
integrations: [
starlight({
title: "My Product Docs",
sidebar: [
{
label: "Getting Started",
items: [
{ label: "Installation", slug: "guides/install" },
{ label: "Quick Start", slug: "guides/quick-start" },
],
},
{
label: "Reference",
// Generate entries from every file in src/content/docs/reference/
items: [{ autogenerate: { directory: "reference" } }],
},
],
}),
],
});Explicit items give you full control over order and labels. autogenerate trades that control for less work as the docs grow: new files under the directory appear in the sidebar automatically, ordered by filename. Most docs sites split the difference: explicit entries for the getting-started path, autogeneration for reference sections.
Search works without a server
Starlight ships with Pagefind, a static search library. When you run astro build, Pagefind indexes the rendered HTML and writes the index into the output directory. Search then runs entirely in the visitor's browser, with no search server to deploy and no per-query cost.
Two things to know:
- Search does not appear in
npm run dev. The index only exists after a build. To test search locally, runnpm run build && npm run preview. - The index is rebuilt on every deploy, so search results match the published content with nothing to invalidate or resync.
Deploy to Railway
Starlight produces static files, so the deployed service is just a file server in front of the dist/ directory. Add the serve package to handle that:
npm install serveThen add a start script to package.json:
{
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"start": "serve dist -l $PORT"
}
}Railway injects the PORT environment variable at runtime, and serve listens on it. serve resolves clean URLs to the folder/index.html files Starlight generates, so /guides/install works without any rewrite rules.
Push the project to GitHub, then:
- Go to railway.com/new and select Deploy from GitHub repo.
- Choose your repository. Railway detects a Node.js project, runs
npm run build, and starts the service withnpm start. - In the service settings, under Networking, click Generate Domain to get a public
*.up.railway.appURL.
Every push to the connected branch now rebuilds the site, including the search index, and deploys the new version.
Add a custom domain
Documentation usually lives at a subdomain like docs.example.com:
- Open your service, go to Settings, and find the Networking section.
- Click + Custom Domain and enter
docs.example.com. - Railway shows two records: a CNAME record and a TXT record that verifies domain ownership. Add both at your DNS provider; the domain will not verify with only the CNAME in place.
- Once both records are in place and verified, Railway provisions and renews the TLS certificate automatically.
See working with domains for provider-specific DNS details, including the Cloudflare proxying caveats.
Keep hosting costs near zero
Railway pricing is usage based, and a static file server uses very little. Two settings help for a low-traffic docs site:
- Serverless: enable it in the service settings and Railway puts the service to sleep after 10 minutes without outbound traffic, then wakes it on the next request. A static server makes no database connections or background calls, so it sleeps reliably. The first request after sleep pays a short cold-start delay. See serverless.
- PR environments: enable them in your project settings and every pull request gets its own preview deployment of the docs, torn down when the PR closes. Reviewers can read the rendered pages instead of raw Markdown diffs. See environments.
Next steps
- Deploy an Astro app for SSR, CLI, and Dockerfile deployment options.
- Deploy static sites for multi-region replicas and CDN integration.
- Working with domains for DNS setup details.
- Serverless for how sleep and wake behavior works.