Static Sites

Deploy static sites and SPAs to Cluster with a public directory.

Static Sites

Cluster can serve static sites — HTML, CSS, JavaScript, images — alongside your handler function. HTML files are inlined into your handler at build time, while other assets are served via the edge CDN.

Getting Started

Use the static template:

ccp init my-site --template static

This creates:

my-site/
  index.ts            # Handler that serves HTML
  public/
    index.html        # Your HTML page
  globals.d.ts        # TypeScript types for __pages
  .cluster/config.json
  package.json

How It Works

When you deploy with --public-dir, the CLI:

  1. Reads all .html files from the public directory
  2. Inlines them as strings into a __pages global object at build time
  3. Uploads all non-HTML files (CSS, JS, images) to the CDN
  4. Your handler serves HTML from __pages, and the CDN serves everything else

The __pages Global

HTML files from your public directory are available as __pages:

export function handler(request: Request): Response {
  return new Response(__pages["index.html"], {
    headers: { "Content-Type": "text/html" },
  });
}

The globals.d.ts file provides the TypeScript type:

declare const __pages: Record<string, string>;

SPA Routing

For single-page apps, serve index.html for all non-asset routes:

export function handler(request: Request): Response {
  const url = new URL(request.url);

  // API routes
  if (url.pathname.startsWith("/api/")) {
    return Response.json({ message: "Hello" });
  }

  // Serve the SPA shell for all other routes
  return new Response(__pages["index.html"], {
    headers: { "Content-Type": "text/html" },
  });
}

Deploying

# Deploy with the public directory
ccp deploy --prod --public-dir public

# Or if .cluster/config.json has "assets": "public"
ccp deploy --prod

The --public-dir flag can also be set permanently in .cluster/config.json:

{
  "assets": "public"
}

CDN Asset Serving

Non-HTML assets (JS, CSS, images, fonts) are served via Cluster's edge CDN with:

  • gzip compression via Traefik
  • 301 redirect from your function domain to the CDN URL
  • Handler-first model for HTML — your handler controls HTML responses, not the CDN

Local Development

ccp dev --public-dir public

Static files are served directly from disk during local dev. Changes to HTML files trigger a hot reload.

On this page