Skip to main content

Deploying Docs to Cloudflare Pages

Why Cloudflare Pages?

  • ✅ Free deployment
  • ✅ Free authentication (Cloudflare Access)
  • ✅ Fast global CDN
  • ✅ Auto-deploy on git push

Setup Instructions

1. Push Your Code to GitHub

git push origin master

2. Sign Up / Log In to Cloudflare

3. Create a New Pages Project

  1. Click "Create application""Pages""Connect to Git"
  2. Connect your GitHub account (jophillips90)
  3. Select the sanctum repository
  4. Click "Begin setup"

4. Configure Build Settings

Production branch: master

Build settings:

  • Framework preset: None (we configure manually)
  • Build command: bash scripts/cf-pages-build.sh
  • Build output directory: docs/build
  • Root directory: / (leave empty or set to root)

Environment variables (Build variables):

  • SKIP_DEPENDENCY_INSTALL: 1required. See "Why the custom build script" below.
  • NODE_VERSION: leave unset.nvmrc and .node-version at the repo root both pin Node 24 (v3 build image reads these; it ignores package.jsonengines). Setting NODE_VERSION in the dashboard overrides the version files and silently drifts; don't do it.

⚠️ If the build fails with engine warnings or pnpm-install errors, first check whether NODE_VERSION was set to an older value in the dashboard. The fix is to delete it and re-deploy.

Why the custom build script (pnpm monorepo pitfall)

This repo is a pnpm monorepo. Cloudflare's default behaviour runs pnpm install --frozen-lockfile at the repo root before the build command, which installs every workspace project (Scope: all 11 workspace projects) — api, web, admin, gdl and their native modules (better-sqlite3, @prisma/engines, @swc/core, esbuild, unrs-resolver, …). The static docs site needs none of that.

Whenever a dependency bump invalidates Cloudflare's dependency cache, that whole native-heavy graph has to be cold-installed inside the build container. It is slow and fragile and surfaces as generic "Build failed" / "Building" errors even though the docs themselves compile fine. This was the root cause of the July 2026 run of failed builds that followed the batch of dependency-upgrade PRs.

The fix (Cloudflare's own recommendation for pnpm monorepos — Skip dependency install):

  1. Set the build variable SKIP_DEPENDENCY_INSTALL = 1 so Cloudflare does not auto-install the whole monorepo.
  2. Point the build command at scripts/cf-pages-build.sh, which runs a scoped install (pnpm install --filter docs... --frozen-lockfile) and then builds only the docs workspace.

Keeping the logic in a committed script (instead of a one-line dashboard field) means it is version-controlled, reviewable, and testable locally:

bash scripts/cf-pages-build.sh

Known Issues

OpenAPI Reference Pages Disabled

docusaurus-plugin-openapi-docs + docusaurus-theme-openapi-docs (5.0.x) declare peer compatibility with Docusaurus ^3.10.0, but at SSG time they end up referencing a different React Context instance than theme-classic's DocItem/Metadata. Every /api/reference/* page then crashes with:

Hook useDoc is called outside the <DocProvider>.

pnpm why @docusaurus/plugin-content-docs confirms "1 version, 2 instances" — same package version, two distinct peer-resolved copies. Neither node-linker=hoisted, public-hoist-pattern=@docusaurus/*, nor dedupe-peer-dependents collapses them.

Workaround (current): the OpenAPI plugin + theme are removed from docusaurus.config.ts, the generated docs/api/reference/*.mdx files are deleted, and the sidebar entry is commented out. The OpenAPI spec is still served as a static asset at /openapi.json for Postman / Insomnia / Scalar consumers.

To re-enable: either pin Docusaurus back to ^3.9 (last known-working combo with plugin 5.0.x) and re-add the plugin + theme + docItemComponent: '@theme/ApiItem' + sidebar entry, or wait for an upstream docusaurus-theme-openapi-docs release that genuinely supports 3.10. Tracked in Notion.

5. Deploy

Click "Save and Deploy"

Cloudflare will:

  • Install dependencies
  • Build the docs
  • Deploy to sanctum-docs.pages.dev

⏱️ Takes about 2-3 minutes

🔐 Add Authentication (Free!)

Enable Cloudflare Access

  1. Go to Zero Trust in Cloudflare dashboard
  2. Navigate to AccessApplications
  3. Click "Add an application""Self-hosted"

Configuration:

  • Application name: Sanctum Docs
  • Session duration: 24 hours (or your preference)
  • Application domain: sanctum-docs.pages.dev

Add Access Policy

Policy name: Email verification

Action: Allow

Configure rules:

  • Selector: Emails
  • Value: Your email addresses (comma-separated)

Example: you@example.com, collaborator@example.com

Or use email domain:

  • Selector: Emails ending in
  • Value: @yourdomain.com

Save and Test

  1. Click "Add application"
  2. Visit your docs site
  3. You'll be prompted to verify your email
  4. Check your email for the login code
  5. Enter code → Access granted!

🔄 Auto-Deploy

Every push to master automatically deploys:

git add docs/
git commit -m "docs: update API reference"
git push
# → Cloudflare auto-deploys in ~2 minutes

📧 Managing Access

Add More Users

Go to Zero TrustAccess → Your application → Edit

Add more emails to the policy.

Revoke Access

Remove emails from the policy or disable the application.

Access Logs

View who accessed your docs: Zero TrustLogsAccess

💰 Cost

100% FREE for:

  • Up to 50 users
  • Unlimited deployments
  • Email authentication
  • Global CDN

🎯 Result

Your documentation will be:

  • ✅ Deployed globally
  • ✅ Protected by email authentication
  • ✅ Auto-updated on every push
  • ✅ Completely free

Only people with verified emails can access it!