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
- Go to dash.cloudflare.com
- Sign up or log in
- Go to Workers & Pages in the sidebar
3. Create a New Pages Project
- Click "Create application" → "Pages" → "Connect to Git"
- Connect your GitHub account (jophillips90)
- Select the
sanctumrepository - 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:1— required. See "Why the custom build script" below.NODE_VERSION: leave unset —.nvmrcand.node-versionat the repo root both pin Node 24 (v3 build image reads these; it ignorespackage.json→engines). SettingNODE_VERSIONin 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_VERSIONwas 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):
- Set the build variable
SKIP_DEPENDENCY_INSTALL = 1so Cloudflare does not auto-install the whole monorepo. - 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
- Go to Zero Trust in Cloudflare dashboard
- Navigate to Access → Applications
- 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
- Click "Add application"
- Visit your docs site
- You'll be prompted to verify your email
- Check your email for the login code
- 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 Trust → Access → 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 Trust → Logs → Access
💰 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!