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@v5A 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:
| Setting | Value |
|---|---|
| Framework Preset | Other |
| Build Command | npm run build |
| Output Directory | site |
| Node.js Version | 22.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.htmlfor a folder's URL, such as/guide/install/fromguide/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
.jsas 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.