snoozestackdocs

Websites

Publish any folder of static files — a Vite/Next export, docs, plain HTML — as a website (public, no keys needed). Declare it in project.toml and it travels with the project: snoozestack dev serves it locally next to the functions it calls, and snoozestack publish takes it live with the backend in the same run:

snoozestack/project.toml
[[sites]]
name = "www"
dir = "dist" # path relative to the project root
primary = true # serves at the project host's root

Every site serves at https://<ref>.snoozestack.com/sites/<site>/. One site is the project's primary site (www by default): it also serves at the root of the project's own host, https://<ref>.snoozestack.com/, so exports built for a domain root work as-is. Move it with snoozestack sites primary <name> or by passing --primary on publish.

A site served under a /sites/<site>/ path must be built with that base path (for Vite, base: '/sites/<site>/'), or its root-absolute /assets/… links will 404. The primary site serves at the root, so a default root build works there unchanged. A custom domain serves both at the same paths, so the base path a site is built with does not depend on which URL it is reached by.

terminal
snoozestack publish # publishes every declared [[sites]] entry, live
# — or, as an ad-hoc one-off outside project.toml:
snoozestack sites publish www --dir ./dist
# Publishing ./dist → site "www" (12 files)…
# ↑ index.html
# ↑ assets/app-3f2c1a.js
# Published: 2 uploaded, 10 unchanged, 0 removed
# ◆ preview: https://preview-<version>-<ref>.snoozestack.com/
# ⇪ live
# https://<ref>.snoozestack.com/

Publishing a site is what makes it live. Each publish also creates a version with its own preview URL, so a specific build stays reachable after later ones supersede it — and snoozestack publish --preview <name> stops at that preview URL, leaving the live site untouched. Locally there is no publishing at all: snoozestack dev serves every declared site's files itself, and the dashboard lists their URLs.

To look before anyone else does, pass --no-promote to sites publish: the version publishes to its preview URL and the site keeps serving what it already serves, until sites promote. Rollback is that same command pointed at an older version id from snoozestack sites versions <name> — there is no separate rollback verb.

A site published here is served from the same host as its project's API, so it can call the API on its own origin — /api/auth, /api/functions/v1, /api/storage/v1 and the rest — instead of building an absolute URL:

src/snoozestack.js
import { createClient } from 'snoozestack-js';
// No project URL to configure, and nothing to change when the site later
// serves from a domain of your own.
export const snoozestack = createClient('/api', SNOOZESTACK_ANON_KEY);

The anon key still belongs in the build — it identifies the project and is safe in a browser; your functions and storage's own access policies are what protect the data, not the key. Only the URL disappears.

The trade is your dev server: on localhost there is no project behind /api, so proxy it there. Keeping the absolute https://<ref>.snoozestack.com URL in an environment variable is a perfectly good alternative — it works in both places without any proxy.

vite.config.js
export default {
server: {
proxy: { '/api': { target: 'https://<ref>.snoozestack.com', changeOrigin: true } },
},
};
Why use it

A single-page app is, after it's built, just files — HTML, JS, CSS, images. Nothing about serving them needs a running server, and putting one in front of them only adds a process to keep alive, patch, and pay for while it does nothing but hand back bytes that never change.

Publishing to object storage instead means the thing serving your frontend has no moving parts to fail: there is no application to crash under load, and traffic spikes are the platform's problem rather than yours. It also keeps the frontend and backend independently deployable — the site talks to your project's API over HTTPS like any other client, so you can ship a UI change without touching the database, or a migration without rebuilding the UI.

The constraint is that this is static hosting only: no server-side rendering, no Node process, no API routes. Frameworks that can export a static build (Vite, React, Next's static export, Astro, plain HTML) work; anything needing a server at request time belongs in an edge function instead.

Your app's frontend
The common case: a Vite or React build published to www, talking to the same project's REST, auth, and storage APIs.
Marketing and docs alongside the app
Publish several sites from one project — www for the landing page, another for docs — each on its own path under the same project.
Preview builds
Publish a branch build under its own site name to share a working URL for review, then delete the site when the branch merges.
Domain-verification files
Apple App Site Association, .well-known files, and search-console tokens are just files in the folder you publish.
SurfaceAvailability
Portal UIList sites, view versions and promote/roll back, delete, set the primary — no publish/upload button
CLIsnoozestack sites publish/versions/promote/list/delete — publishing is a CLI-only operation
SDK / HTTPNone — publishing is a build-time step, not something an app calls at runtime

A publish is a content sync against the project's site storage (created on first publish): files whose MD5 matches the stored ETag are skipped, changed and new files are uploaded, and files deleted locally are removed remotely. Re-running a publish with no changes is a no-op.

  • Directory URLs (and the site root) serve that directory's index.html; extension-less paths redirect to their trailing-slash form.
  • Misses render the site's 404.html if present.
  • HTML is served no-cache so a republish shows immediately; other assets get a 5-minute cache.
  • Content types come from file extensions (html, css, js, images, fonts, wasm, …).
  • The bucket is private, and deleting the site (or project) stops serving immediately.
  • Every served request is logged under Logs → Websites; per-site sizes and file counts are on the Websites page itself, and who published what is under Observability → Audit log.

Connecting a custom domain adds a second front door rather than replacing this one. Both serve every site at the same paths — the primary one at the root (example.com/), every other at /sites/<name>/ — so publishing does not change and no site needs a name of its own. The link on each row points at whichever URL the project is currently handing out; the other keeps working either way.

The /api base#

The base URL your apps point at — https://<ref>.snoozestack.com/api — exists as soon as the project does, with nothing to turn on: caching is disabled there and all methods pass through to the project's runtime. A connected domain serves the same paths under its own /api, which is why a site published here should use the relative /api form — it then stays correct wherever it is served from.