Deployment

A ShellDocs site is a Blazor Web App. You can run it on a .NET host, or export it to static files with shelldocs build and serve those from any static host. This site runs on a .NET host, as a Docker image.

Choosing

Prop Type Default Description
Static export shelldocs build — Plain HTML, CSS and JS. Free or cheap hosting, nothing to keep running. Search works. Demos with event handlers render but do not respond.
A .NET host dotnet publish — Everything works, including demos with event handlers. Needs a server or container that runs ASP.NET Core.

What works on a static export

shelldocs build prerenders every page. The chrome is written so its initial state comes from the server and shelldocs.js handles the clicks, which means most of it needs no Blazor runtime.

Prop Type Default Description
Page content and navigation works — Every page is a real HTML file. Links are ordinary links.
Sidebar sections works — Expand and collapse. The section holding the current page starts open.
Package and version selectors works — Menus open and close, options are links.
Table of contents works — Highlights the heading in view.
Theme toggle works — Remembers the choice in localStorage.
Tabs and CodeGroup works — Including sync groups.
Preview frames works — Preview and Code tabs, copy, the actions menu.
Mobile navigation works — The drawer opens, closes on a link, the backdrop or Escape.
Redirects works — Written as redirect pages.
Search works — The index is a file in the export and is ranked in the browser. See below.
Collapsing the whole sidebar works — The desktop collapse button. The choice is remembered across pages.
Not-found page works — Written as 404.html, which most static hosts serve for unknown URLs. It names the address the reader asked for.
llms.txt and agent files works — Written into the export as files, with the page actions menu working. See AI agents (llms.txt).
Demos with event handlers needs a server — A demo that reacts to clicks renders in its initial state and does not respond.

The app serves its search index at /_shelldocs/search.json, and shelldocs build copies that file into the export. shelldocs.js fetches it the first time a reader opens search and ranks it in the browser, with the same scoring on a static host as on a .NET host. Nothing is sent to a server, and there is no external service to set up. More in Search.

The site and the CLI both need to be on 0.1.15-alpha or later. shelldocs build warns when the site's ShellDocs.Components is too old to serve an index.

What still needs a server

A demo with @onclick handlers, or any other Blazor event handler, needs a running app. On a static export it renders in its initial state and does not respond. If your docs depend on live demos like that, run the site on a .NET host.

Building the static site

bash
dotnet tool install -g ShellDocs.CLI --prerelease
shelldocs build --site-url https://docs.example.com

The output goes to ./publish. Every flag is covered in shelldocs build. Two matter for hosting:

  • --site-url adds sitemap.xml, robots.txt and social-preview meta tags.
  • --base-href is needed only when the site is served from a subpath, such as a GitHub project page at /my-repo/.

GitHub Pages

This workflow builds on every push to main and can be run by hand.

yaml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: pages
  cancel-in-progress: true

permissions:
  pages: write
  id-token: write
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          global-json-file: global.json
      - run: dotnet tool install -g ShellDocs.CLI --version 0.1.17-alpha
      - run: shelldocs build --site-url https://docs.example.com
      - run: echo "docs.example.com" > publish/CNAME
      - run: touch publish/.nojekyll
      - uses: actions/upload-pages-artifact@v3
        with:
          path: publish

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v4

Three lines are easy to miss:

  • .nojekyll : GitHub Pages runs Jekyll by default, and Jekyll drops folders that start with an underscore. Blazor's assets live in _framework and _content, so without this file the site loads with no styles or scripts.
  • CNAME : keeps a custom domain attached across deploys. Leave the step out if you use the default github.io address.
  • Pin the CLI version to the version of the ShellDocs packages your project references, so a new prerelease can't change the build under you.

One-time setup

  1. Set the Pages source

    In the repository, open Settings, then Pages, and set Source to GitHub Actions. Until this is done the deploy job fails with a 404 from the Pages API.

  2. Add the custom domain

    On the same page enter the domain under Custom domain and save.

  3. Point DNS at GitHub

    At your DNS provider add a CNAME record for the subdomain with the value your-org.github.io. If the provider proxies traffic, turn the proxy off for this record until the certificate is issued.

  4. Wait for the certificate, then enforce HTTPS

    GitHub requests a certificate once the DNS check passes. When it arrives the Enforce HTTPS box becomes available.

If the certificate never arrives, check CAA records

GitHub Pages certificates come from Let's Encrypt. A CAA record on the parent domain that names only another authority blocks it, with no error shown. This happens when another platform manages the apex domain and added its own record. Add a second record, 0 issue "letsencrypt.org", next to the existing one, then remove and re-add the custom domain in the Pages settings to restart the request.

Project pages

For a site served at https://your-org.github.io/my-repo/, drop the CNAME step and pass the subpath:

bash
shelldocs build --base-href /my-repo/

Other static hosts

Any host that serves a folder works: point it at publish. Many hosts' own build environments don't include the .NET SDK, so the dependable setup is to run shelldocs build in CI and upload the output, as the workflow above does.

Running on a .NET host

Publish and run it like any ASP.NET Core app.

bash
dotnet publish -c Release -o out
dotnet out/MyDocs.Docs.dll

The content folder must be in the publish output. shelldocs init adds the project items that copy it:

xml
<ItemGroup>
  <Content Include="content/**/*.md" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
  <Content Update="content/**/meta.json" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>

Any platform that runs ASP.NET Core works: a container, a virtual machine, or a managed app service.

See also