StaticSite
Source:
src/Cloudflare/Website/StaticSite.ts
A Cloudflare Worker that serves static assets built by a shell command.
StaticSite runs a build command (e.g. npm run build), content-hashes
the output directory, and deploys the result as a Cloudflare Worker with
static assets. Use this when your site has its own build step that
produces a directory of files — Hugo, Zola, Eleventy, or any custom
pipeline.
For Vite-based projects, prefer Cloudflare.Website.Vite which handles
building automatically.
Basic Usage
Section titled “Basic Usage”Point command at your build script and outdir at where it writes
output. Alchemy runs the command, hashes the output, and deploys it as
an assets-only Worker — no Worker code is uploaded, and Cloudflare’s
asset layer serves every request itself.
Deploying a Hugo site
const site = yield* Cloudflare.Website.StaticSite("Blog", { command: "hugo --minify", outdir: "public",});Provide main to put your own Worker in front of the assets instead.
The Worker receives an ASSETS binding it can delegate to:
export default { fetch: (request: Request, env: { ASSETS: Fetcher }) => env.ASSETS.fetch(request),};Custom Worker in front of the assets
const site = yield* Cloudflare.Website.StaticSite("Blog", { command: "hugo --minify", outdir: "public", main: "./src/worker.ts",});Asset Configuration
Section titled “Asset Configuration”Use assets to control how Cloudflare handles routing for
your static files — HTML handling, not-found behavior, etc.
const site = yield* Cloudflare.Website.StaticSite("App", { command: "npm run build", outdir: "dist", main: "./src/worker.ts", assets: { htmlHandling: "auto-trailing-slash", notFoundHandling: "single-page-application", },});Building from a Subdirectory
Section titled “Building from a Subdirectory”Set cwd to run the build command in a subdirectory (e.g. a
monorepo package). outdir is resolved relative to cwd.
const site = yield* Cloudflare.Website.StaticSite("Web", { cwd: "apps/web", command: "npm run build", outdir: "dist", main: "apps/web/worker.ts",});Custom Rebuild Scope
Section titled “Custom Rebuild Scope”By default, all non-gitignored files are hashed to decide whether
the build should re-run. Use memo to narrow the scope.
Narrowing the memo scope
const site = yield* Cloudflare.Website.StaticSite("Docs", { command: "npm run build", outdir: "dist", main: "./src/worker.ts", memo: { include: ["content/**", "templates/**", "config.toml"], },});Rebuilding when a sibling workspace package changes
The default scope only hashes files under cwd (plus the nearest
lockfile), so edits to a sibling workspace package the app imports do
not retrigger the build on their own. Add the sibling’s sources with a
../ include glob — and keep lockfile: true, since providing
include otherwise drops the lockfile from the hash:
const site = yield* Cloudflare.Website.StaticSite("Web", { cwd: "apps/web", command: "npm run build", outdir: "dist", main: "./src/worker.ts", memo: { include: ["**\/*", "../../packages/env/src/**"], lockfile: true, },});Class Form
Section titled “Class Form”Calling StaticSite with no arguments returns a constructor you can
extend to declare the Worker as a named class. The class is both
an Effect you can yield* to deploy and a type you can reference
elsewhere — useful when other resources need to bind to this Worker.
class Blog extends Cloudflare.Website.StaticSite<Blog>()("Blog", { command: "hugo --minify", outdir: "public", main: "./src/worker.ts",}) {}
const site = yield* Blog;