Deploy any framework
Host any framework — static or server-rendered — Astro, SvelteKit, Next.js, Nuxt, Qwik, React Router, and more — by publishing the build output
shiply hosts any framework — static or server-rendered. The one rule: publish the build output, never the source code. Static builds (HTML, hashed JS bundles, CSS, assets) serve straight from the edge. Server-side frameworks — SvelteKit, Astro, Qwik, Nuxt and the rest of the Nitro family (SolidStart, Analog, TanStack Start), React Router v7, and Next.js — deploy as a per-site Cloudflare Worker that runs your SSR on every request.
The CLI auto-detects 16+ frameworks. Run shiply publish . in your project
and it either publishes the build output for you (with the right flags) or
prints the exact build command to run first. Preview what it found with
shiply detect.
Auto-detected frameworks
| Framework | Build output | SPA mode |
|---|---|---|
Next.js (output: 'export') | out/ | no |
| Next.js (SSR via OpenNext) | deployed as a Worker bundle — see Next.js | — |
| Astro | dist/ | no |
| SvelteKit (adapter-static) | build/ | yes |
| Vite (React/Vue/Svelte/Solid/Qwik) | dist/ | yes |
| Create React App | build/ | yes |
Nuxt (nuxt generate) | .output/public/ | no |
| Remix (client build) | build/client/ | yes |
| Docusaurus | build/ | no |
| Hexo | public/ | no |
| SolidStart (static preset) | dist/public/ | no |
| Qwik City (static adapter) | dist/ | no |
| Hugo | public/ | no |
| Jekyll | _site/ | no |
| Eleventy | _site/ | no |
| MkDocs | site/ | no |
| Plain HTML / pre-built output | any folder with index.html | optional |
Anything else that produces a dist/, build/, out/, _site/, public/,
or .output/public/ folder with an index.html is picked up by the generic
fallback.
React / Vue / Svelte / Solid / Qwik (Vite)
npm run build
shiply publish dist --spa--spa makes deep links like /about fall back to index.html, so the
client router handles the route instead of 404ing.
Create React App
npm run build
shiply publish build --spaNext.js
shiply deploys Next.js server-side via OpenNext.
Server features (getServerSideProps, route handlers, server actions) run on a
per-site Cloudflare Worker. Build, then publish:
next build --webpack # Next 16 defaults to Turbopack; OpenNext needs the webpack build
npx @opennextjs/cloudflare build
shiply publish .Plain SSR is live and verified on prod. ISR / on-demand revalidate is not
supported yet — those routes run as live SSR for now. Prefer a fully static
site? Set output: 'export' in next.config.ts, run npm run build, and
shiply publish out.
Astro
npm run build
shiply publish distSvelteKit
For a server-rendered app, use
@sveltejs/adapter-cloudflare —
shiply detects the adapter output and deploys your SSR as a per-site Worker:
npm run build
shiply publish .For a fully static build, use
@sveltejs/adapter-static instead
and shiply publish build --spa.
Nuxt
For a server-rendered app, build with the Nitro cloudflare preset, then
publish from the project root — shiply detects the Nitro cloudflare output
(.output/nitro.json + .output/server/index.mjs) and deploys SSR as a
per-site Worker:
NITRO_PRESET=cloudflare_module npm run build
shiply publish .(You can also set nitro: { preset: 'cloudflare_module' } in nuxt.config
instead of the env var.) Dynamic routes, server routes, and API handlers run
at the edge.
For a fully pre-rendered static site, nuxt generate writes a real HTML file
per route:
npx nuxt generate
shiply publish .output/publicReact Router v7 (formerly Remix)
shiply deploys React Router v7 framework-mode apps server-side. Build with the
Cloudflare Vite plugin, then publish — shiply detects the built
build/server/index.js, deploys SSR as a per-site Worker, and serves
build/client assets first:
npm run build
shiply publish .For a static client-only build, shiply publish build/client --spa serves the
pre-built assets without the server runtime.
Docusaurus
npm run build
shiply publish buildHugo / Jekyll / Eleventy / MkDocs
Classic static site generators. Build, then publish the output folder —
no --spa flag (every route is a real HTML file):
# Hugo
hugo && shiply publish public
# Jekyll
bundle exec jekyll build && shiply publish _site
# Eleventy
npx @11ty/eleventy && shiply publish _site
# MkDocs
mkdocs build && shiply publish siteHexo / SolidStart / Qwik City
SolidStart and Qwik City can deploy server-side — build with the Cloudflare
preset/adapter and run shiply publish .; shiply detects the SSR output and
deploys a per-site Worker. Static builds work too:
# Hexo (static)
npx hexo generate && shiply publish public
# SolidStart (Nitro cloudflare preset → SSR)
npm run build && shiply publish .
# Qwik City (@builder.io/qwik-city cloudflare-pages adapter → SSR)
npm run build && shiply publish .Override detection
If auto-detection picks the wrong framework, force it:
shiply publish . --framework=astroRun shiply detect to see what was matched, which build command will run,
and which folder will be published — without uploading anything.
Updates keep the same URL
Re-running shiply publish in the same directory updates the same site at
the same URL — state lives in .shiply.json next to your build output, and
unchanged hashed bundles are skipped, so updates upload only what changed.
Tips
- Agents: prefer the CLI over inline MCP uploads for built apps — a production build often has 100+ hashed files, beyond the 50-file inline cap.
- Limits: 1,000 files per site, 100 MiB per file, 1 GiB per site.
- Calling APIs that need a secret key? Don't embed keys in your bundle — store them in Variables.