SSG
LitMDX now prerenders each known route during litmdx build.
That means the output is no longer just one SPA entry file. Instead, the build writes HTML files per route, for example:
dist/
├── index.html
├── basics/
│ └── index.html
├── basics/project-structure/
│ └── index.html
├── features/sitemap/
│ └── index.html
└── reference/configuration/
└── index.htmlEach generated HTML file already contains:
- The rendered page content
- The page title
- The page description
- Route-specific
og:title,og:description, andog:url - The same client bundle used for hydration and navigation after load
Why this matters
SSG improves three things immediately:
- Faster first paint: users receive real HTML instead of an empty shell.
- Better SEO: crawlers can read page content and metadata without executing the app first.
- Better social previews: route HTML already includes the correct Open Graph metadata.
What still stays client-side
LitMDX still hydrates into a client app after load, so you keep:
- Client-side navigation
- Theme switching
- Search modal
- Copy actions
- WebMCP integration
So the model is: static first render, SPA after hydration.
Unknown routes and 404s
Known routes are now real files, so /basics or /reference/configuration can be served directly by any static host.
Unknown routes are different: if a user opens a path that was not generated at build time, only the client app knows how to show LitMDX's built-in 404 page. For that reason, an optional SPA fallback rule is still useful if you want consistent 404 behavior.
baseUrl support
SSG now honors baseUrl explicitly.
If your docs are deployed under a subpath such as:
https://example.com/my-docs/
then LitMDX now adjusts:
- Asset URLs, such as
/my-docs/assets/... - Prerendered internal links, such as
/my-docs/basics - Search asset loading, such as
/my-docs/pagefind/pagefind.js - Route-specific Open Graph URLs
sitemap.xmlentries whensiteUrlis also configured
That makes the prerendered output compatible with subpath deployments like GitHub Pages project sites.
Typical configuration:
export default defineConfig({
baseUrl: '/my-docs/',
siteUrl: 'https://example.com',
});This produces canonical URLs like https://example.com/my-docs/basics while still writing the deployable static files into dist/.

