Astro
Create an Astro documentation site with Heyo Docs, or integrate the smallest static setup into an existing project.
For a new documentation site, start with create-heyo-docs. The Astro template
connects the content pipeline to Astro, generates every known documentation
path at build time, hydrates the documentation UI as a React island, and keeps
the optional API request proxy separate from static content.
Recommended: create a project
Use the creator with the Astro template. Remove the flags if you would rather pick the template, deployment, theme, and package manager in the wizard.
bun create @heyo-sh/heyo-docs my-docs --template astrocd my-docsbun run devThe generated site is a standalone documentation project rather than an
installation inside another Astro app. Its content/ directory contains the
source MDX, while heyo-docs.config.ts defines navigation, branding, metadata,
and the active theme.
Manual, minimal installation
Use the following integration when docs belong inside an existing Astro site. It is deliberately the smallest useful setup: static MDX routes and the documentation UI. Use the generated project when you also need the theme switcher, icon mapping, resource routes, OpenAPI reference pages, or the server-side Try it proxy.
1. Install the integration
This assumes that the existing project uses Astro with the React integration and Tailwind v4. Add the missing packages if it does not.
bun add @heyo-sh/heyo-docs @astrojs/react @fontsource-variable/figtree shadcn tw-animate-cssbun add -d @tailwindcss/vite tailwindcss2. Add configuration and content
Create heyo-docs.config.ts at the project root:
import { heyoDocs } from "@heyo-sh/heyo-docs";
export default heyoDocs({
title: "Acme Docs",
description: "Documentation for Acme.",
content: "content",
theme: "grain",
groups: [
{
group: "Documentation",
sections: [{ section: "Get started", pages: ["index"] }],
},
],
branding: { name: "Acme" },
});Add content/index.mdx:
---title: Welcomedescription: Start here.---# WelcomeYour documentation is ready.3. Connect Astro and the theme
heyoDocsAstro registers the Vite-powered MDX/content pipeline with Astro.
Setting output: "static" tells Astro to emit the documentation paths during
the build.
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import tailwindcss from "@tailwindcss/vite";
import { heyoDocsAstro } from "@heyo-sh/heyo-docs/astro";
import config from "./heyo-docs.config";
export default defineConfig({
integrations: [react(), heyoDocsAstro({ config })],
output: "static",
vite: { plugins: [tailwindcss()] },
});@import "@fontsource-variable/figtree";@import "@heyo-sh/heyo-docs/theme/grain.css";:root { --heyo-docs-font-family: "Figtree Variable", sans-serif;}4. Add a static catch-all page
Create a small React island for the documentation UI. This minimal version uses regular links; the generated template adds client-side navigation, icons, and a persisted colour-mode control.
import { DocsApp } from "@heyo-sh/heyo-docs";
import config from "../../heyo-docs.config";
import { pages } from "virtual:heyo-docs-content";
export function AstroDocsApp({ pathname }: { pathname: string }) {
return <DocsApp config={config} pages={pages} pathname={pathname} />;
}Then render it from src/pages/[...slug].astro. getStaticPaths() keeps the
route list in sync with the same pages used in the sidebar.
---import { AstroDocsApp } from "../components/docs-app";import "../styles/app.css";import { pages } from "virtual:heyo-docs-content";export function getStaticPaths() { return pages.map(({ slug }) => ({ params: { slug: slug === "/" ? undefined : slug.slice(1) }, }));}const pathname = Astro.params.slug ? `/${Astro.params.slug}` : "/";---<AstroDocsApp client:load pathname={pathname} />Run bun run dev and open /. For a hybrid deployment with the optional
request proxy, or for generated OpenAPI pages, use the complete Astro template
from create-heyo-docs; its adapter and resource routes handle that boundary.
Development feedback
Saving an MDX file while bun run dev is running refreshes the page without a
server restart. output: "static" controls astro build, not local
development; deployed content changes still require a fresh build and deploy.
Rendering strategy for the Astro template
This rendering strategy applies to the Astro template generated by
create-heyo-docs.
The Astro template treats documentation as a release artefact. MDX pages,
OpenAPI navigation, endpoint payloads, Markdown mirrors, and discovery files
are produced during astro build and can be served from a CDN. A deployed
server exists only for the optional Try it proxy; it is not involved in
reading or rendering documentation content.
flowchart LR A[MDX and OpenAPI sources] --> B[astro build] B --> C[Static HTML and assets] B --> D[Endpoint JSON shards] C --> E[CDN] D --> E F[Try it POST] --> G[Astro adapter function or Worker] G --> H[Declared API server]
Why this model
Documentation changes are published through a build and deployment. Rendering the same MDX and OpenAPI model again for every reader would add latency and runtime cost without making the documentation fresher. Static output instead provides predictable cacheability, low time to first byte, and resilience when the application runtime is unavailable.
The template configures Astro with output: "static". Its catch-all
documentation and Markdown routes export getStaticPaths(), using the
build-generated MDX page list and OpenAPI endpoint index. Every known path is
therefore emitted during the build, including generated API-reference pages.
OpenAPI data delivery
The browser receives a compact endpoint index for sidebar navigation and search. Detailed content is split into static JSON files below:
/_heyo-docs/openapi/<group>/<tag>/<operation>.jsonFor each prerendered API route, Astro also serialises that route’s detailed payload into the static island input. The server-rendered HTML and the hydrated React component therefore begin with the same complete endpoint data: opening an API page does not first show a compact version and then replace it with a richer UI. There is no endpoint-detail request or layout shift on the initial page load.
The JSON shard remains a public, cacheable static artefact for integrations and future prefetching. Each payload contains the endpoint’s request, response, examples, security metadata, and only the component schemas reachable from that endpoint. It intentionally does not duplicate the complete OpenAPI document in the shared browser bundle.
The one dynamic route
POST /heyo-docs-internal/openapi-request remains on demand and is marked with
export const prerender = false. It is used only when a reader selects Send
request. The handler validates that the selected server is declared by the
OpenAPI document, then performs the request server-side. This avoids browser
CORS limitations and keeps the documentation site from becoming an unrestricted
open proxy.
Astro still needs a deployment adapter for this route. The generated project uses the Node adapter by default; the Cloudflare and Vercel deployment overlays replace it with their respective adapter. Static pages and endpoint JSON remain cacheable assets on all three targets.
Operational implications
- Editing MDX or an OpenAPI schema requires a build and redeploy.
- Remote schemas are fetched during the build, so pin their URL or commit for reproducible releases.
- Build time and output size grow with the number of generated API routes. This is deliberate: every route is available as static content immediately after deployment.
- The
Try itproxy can be removed if interactive requests are not required; the rest of the documentation remains fully static.
What is not dynamic
Theme selection, local search, sidebar navigation, and endpoint rendering are browser interactions backed by static page data and assets. They do not require Astro SSR. The adapter function is reserved for actions that genuinely need a server: currently the optional API request proxy.