Docusaurus & static builds
thin.host hosts the output of any static-site generator — Docusaurus, Astro, Vite, VitePress, Hugo, Next output: 'export' — and an agent can deploy it in one tool call. This page is the Docusaurus recipe; the same flow works for the others. Prefer to hand this to Claude Code? Install the thin-host-docusaurus skill (curl -o ~/.claude/skills/thin-host-docusaurus/SKILL.md --create-dirs https://thin.host/skills/thin-host-docusaurus/SKILL.md) and say "deploy my docs".
What you get
- One call to publish.
publish_website(source_path="…/build", title, slug)uploads the whole folder — hundreds of files are batched across requests automatically. - Clean redeploys.
update_website(…, sync=true)uploads the new build and deletes every file the old one left behind, so renamed hashed chunks never pile up. - Custom domain with TLS, plus generated
robots.txt,sitemap.xml, and canonical tags on it. - Your own 404. The build's
404.htmlbecomes the site's not-found page and is served with a real 404 status. - Password or email gating for the whole site or single pages, set in the dashboard and kept across redeploys.
- Redirects that survive. Redirect pages you author in the dashboard are never pruned by a sync.
1. Decide the baseUrl
Docusaurus bakes baseUrl into every asset URL. Where the site will be viewed decides the value:
| Where readers will look | baseUrl | Notes |
|---|---|---|
A custom domain, e.g. docs.example.com | / | The normal case. The thin.host preview URL renders unstyled until the domain is mapped — expected, not a bug. |
The preview URL https://thin.host/s/<slug>/ | /s/<slug>/ | Pick the slug first and pass it to publish_website. |
Make it switchable so both builds come from one repo:
// docusaurus.config.ts
url: 'https://docs.example.com',
baseUrl: process.env.DOCUSAURUS_BASE_URL ?? '/',
# custom-domain build (default)
npm run build
# preview build for the shared thin.host origin
DOCUSAURUS_BASE_URL=/s/example-docs/ npx docusaurus build --out-dir build-preview
The publish tools detect Docusaurus and report base_url. When it will not resolve at the returned URL the response carries a warning that says exactly this — an agent should relay it rather than debug a "blank" site.
2. Publish
publish_website(
source_path="/abs/path/to/repo/build",
title="Example Docs",
slug="example-docs", # needed if you built with baseUrl '/s/example-docs/'
)
# → { url: "https://thin.host/s/example-docs/", page_count: 277, asset_count: 400,
# requests: 5, framework: "docusaurus", base_url: "/", warning: "…" }
Or from Claude Code, in words: "Build the docs and publish the build folder to thin.host as example-docs."
3. Redeploy with sync
update_website(
website="example-docs", # slug, id, or live URL
source_path="/abs/path/to/repo/build",
sync=True,
)
# → { removed_assets: ["/assets/js/main.0a1b2c3d.js", …], kept_redirects: [], … }
Always pass sync=true for a build folder. Without it the site keeps working, but every previous build's chunks stay forever. Sync is safe to re-run; a deploy that fails partway says which request failed, and running it again finishes the job.
No local server? Publish a zip
Through the hosted endpoint (https://thin.host/mcp, or any agent without a local MCP server) the build travels as a zip. Either upload it directly:
cd build && zip -qr ../site.zip . && cd ..
curl -X POST https://thin.host/v1/websites/example-docs/archive \
-H "Authorization: Bearer $THIN_HOST_API_KEY" -F file=@site.zip # sync=true by default
…or put the zip somewhere public and let the agent call publish_website_from_url / update_website_from_url with that link. Both apply the same mapping, baseUrl detection and sync rules as the local tools.
4. Map the domain
Dashboard → the website → Domains → add docs.example.com and create the CNAME shown. TLS provisions automatically, secondary hostnames 301 to the primary, and robots.txt / sitemap.xml are generated for the domain. An agent can instead call provision_domain and hand the user the claim URL.
Protecting the docs
Password- or email-gate the whole site, or single pages, from the dashboard. Gating is stored on the page, and a redeploy updates pages in place, so it survives. Leave /404 unprotected — a gated 404 page is not used for misses.
REST, for CI
Everything above is three endpoints. Split the build into batches of at most 20MB, 200 pages, and 500 assets each:
# create (first batch) → note the slug
curl -X POST https://thin.host/v1/websites -H "X-Platform-API-Key: $THIN_HOST_API_KEY" \
-H "Content-Type: application/json" -d @batch-0.json
# remaining batches — assets first, then pages
curl -X PATCH https://thin.host/v1/websites/example-docs -H "X-Platform-API-Key: $THIN_HOST_API_KEY" \
-H "Content-Type: application/json" -d @batch-1.json
# prune with the full manifest
curl -X POST https://thin.host/v1/websites/example-docs/sync -H "X-Platform-API-Key: $THIN_HOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"keep": {"pages": ["/", "/docs/intro", "/404"], "assets": ["/assets/js/main.e7f12ca1.js", "…"]}}'
Full field reference: REST API · MCP tools.
Supported files
.html files become pages (docs/intro/index.html → /docs/intro, 404.html → /404). Assets: css, js, mjs, map, png, jpg, jpeg, gif, svg, ico, webp, avif, mp4, webm, mp3, woff, woff2, ttf, otf, eot, wasm, json, xml, txt, csv, md, yaml, yml, pdf, webmanifest. Anything else (for example .nojekyll) is skipped and listed in skipped_files. Single files over ~15MB do not fit a request — compress or drop them.