GitHub Pages

On this page

There are two ways to publish to GitHub Pages from GitHub Actions, and both are stable: GitHub's own Pages actions upload dist/, or the git adapter pushes it to a branch.

Set Settings > Pages > Source to GitHub Actions. The workflow builds and checks the site, and GitHub's own actions publish dist/; no deploy setting is needed.

# .github/workflows/pages.yml
name: Pages
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
concurrency:
  group: pages
  cancel-in-progress: true
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.pages.outputs.page_url }}
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx kilim build
      - run: npx kilim check --format github
      - uses: actions/upload-pages-artifact@v5
        with:
          path: dist
      - id: pages
        uses: actions/deploy-pages@v5

Set url in the config to the Pages address so canonical links and the sitemap point there. Kilim builds a site for the root of its domain and url takes no path, so publish to a user or organization site (https://<user>.github.io) or a custom domain rather than a project path such as /<repo>/.

With a gh-pages branch (git adapter)

The git adapter commits the build to a branch and pushes it. It works from your machine and from Actions; set Settings > Pages > Source to Deploy from a branch, gh-pages, / (root).

import { defineConfig } from "@kilim-dev/core";
import { git } from "@kilim-dev/core/adapters";

export default defineConfig({
  url: "https://www.example.com",
  deploy: git({ branch: "gh-pages", cname: "www.example.com" }),
});

Options: remote (default origin), branch (default gh-pages), message, cname (writes a CNAME file for a custom domain) and nojekyll (default true, so GitHub serves _kilim/). The commit is made outside your working tree; your branches and index are not touched, and the push is never forced.

In Actions, actions/checkout leaves credentials that can push to the repository:

permissions:
  contents: write
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npx kilim deploy