Deployment

dotnet publish writes the site to dist/ as static files only, ready to upload to any static host. Before publishing, set SiteInfo.BaseUrl to the site's final public URL; Kiji uses it for page, feed, sitemap, and image URLs.

Publish under a subpath

When the site is not at the domain root, such as a GitHub Pages project site, include the path in BaseUrl:

BaseUrl = new Uri("https://your-name.github.io/my-site/"),

Build page links with Site.ResolveUrl and asset links with Assets; both then include /my-site/. Links written as /docs/ do not.

@inject SiteInfo Site

<a href="@(Site.ResolveUrl("docs/").AbsolutePath)">Docs</a>
<link rel="stylesheet" href="@Assets["css/app.css"]" />

The path does not become a directory in dist/: upload the contents of dist/ so that dist/index.html is served at /my-site/. The development server uses the same path, at http://localhost:8080/my-site/, and returns 404 outside it, so a missing base path shows up before deployment.

GitHub Pages with Actions

In the repository settings, set the Pages source to GitHub Actions, then add this workflow, replacing MySite with the project directory:

name: Deploy site

on:
  push:
    branches: [main]
  workflow_dispatch:

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

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

jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-dotnet@v6
        with:
          dotnet-version: "10.0.x"

      - run: dotnet publish MySite

      - uses: actions/configure-pages@v6
      - uses: actions/upload-pages-artifact@v5
        with:
          path: MySite/dist
      - id: deployment
        uses: actions/deploy-pages@v5

Other static hosts

On Netlify, Vercel, Cloudflare Pages, and similar services, use dotnet publish as the build command and dist as the output directory. The build environment needs the .NET 10 SDK; otherwise, publish in your own CI and upload dist/.

Check that the host serves about/index.html for /about/ and uses 404.html, written by AddNotFoundPage, for unmatched paths.

Compression

Kiji can also precompress your site. Add this to the project's <PropertyGroup>:

<CompressionEnabled>true</CompressionEnabled>

Publishing then writes .gz and .br copies of compressible files next to the originals. Servers configured to send precompressed files, such as nginx with gzip_static or Caddy with precompressed, send these copies as is instead of compressing each response. The copies are made at publish time, so publish again after changing the site rather than editing files in dist/.

GitHub Pages, Netlify, Vercel, and Cloudflare Pages compress responses themselves, so leave the setting off for them; it is off by default.