Deploy

markupress build writes a static site to site/: an index.html per page in a folder named by its URL, a 404.html, the assets under _markupkit/, and the files in public/. Any host that serves static files serves it. A build script in the site's package.json gives every host one command:

{
  "scripts": {
    "dev": "markupress dev",
    "build": "markupress build",
    "preview": "markupress preview"
  }
}

The build runs on Node 22.22.2 or later in Node 22, or Node 24.15 or later in Node 24, so set the host's Node version to one of those.

Base path

base is the URL path the site is served under, / by default. Set it when the site lives in a subfolder of its domain, such as a GitHub Pages project site at https://<owner>.github.io/<repository>/:

// markupress.config.ts
import { defineConfig } from 'markupress';

export default defineConfig({ base: '/my-project/', origin: 'https://my-org.github.io' });

Every page, asset and link carries the base, and --base on the command line takes the configured value's place for one build: markupress build --base /preview/. With origin set, build also writes sitemap.xml (see SEO).

markupress preview serves the built site under its base, so it shows what the host serves.

GitHub Pages

A workflow builds the site and deploys it with GitHub's Pages actions. In the repository's settings, under Pages, set the source to GitHub Actions, then add .github/workflows/pages.yml:

name: Documentation site
on:
  push:
    branches: [main]
  workflow_dispatch:
permissions:
  contents: read
  pages: write
  id-token: write
concurrency:
  group: pages
  cancel-in-progress: false
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0   # the full history dates each page by its last commit
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-pages-artifact@v5
        with:
          path: site
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v5

A project site's base is /<repository>/; a user or organization site, or a site with a custom domain, uses /. GitHub Pages serves 404.html for every missing path. This documentation deploys with the same workflow.

Vercel

Import the repository in Vercel, and in the project's settings:

SettingValue
Framework PresetOther
Build Commandnpm run build
Output Directorysite
Node.js Version22.x or 24.x

Vercel serves 404.html for missing paths, and base stays / unless the site is served under a path of its domain.

Netlify

A netlify.toml at the repository root configures the build:

[build]
  command = "npm run build"
  publish = "site"

[build.environment]
  NODE_VERSION = "24"

Netlify serves 404.html for missing paths, and base stays / unless the site is served under a path of its domain.

Any static host

Upload the contents of site/ to the folder the host serves at the site's base. The host:

  • serves index.html for a folder's URL, such as /guide/install/ from guide/install/index.html;
  • serves 404.html, with status 404, for missing paths, if it supports a custom not-found page;
  • serves files by their extension's media type, including .js as JavaScript.

Pages carry their Content Security Policy in a <meta> element, so the host needs no headers for it. A page's redirectFrom front matter and MarkupKit's redirects option write an HTML page at each old URL, which sends the reader to the new one, so redirects work on any host.

Pages and history

Each page shows the date its file last changed, from git. A build in a checkout with only recent history dates each file by its oldest fetched commit, so a host's build fetches the full history to show the dates, as fetch-depth: 0 does on GitHub Actions. Outside a git checkout, pages show no date.

Edit this page

Last updated