Websites
Publish any folder of static files — a Vite/Next export, docs, plain HTML — as a website (public, no keys needed). Every site serves at https://<ref>.shovelbase.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>.shovelbase.com/, so exports built for a domain root work as-is. Move it with shovelbase 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 and any site behind a custom domain serve at root, so a default root build works there unchanged.
shovelbase sites publish www --dir ./dist# Publishing ./dist → site "www" (12 files)…# ↑ index.html# ↑ assets/app-3f2c1a.js# Published: 2 uploaded, 10 unchanged, 0 removed# https://<ref>.shovelbase.com/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 S3'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 —
wwwfor the landing page, another for docs — each on its own path or its own subdomain. - 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-knownfiles, and search-console tokens are just files in the folder you publish.
| Surface | Availability |
|---|---|
| Portal UI | List sites, delete, attach a subdomain — no publish/upload button |
| CLI | shovelbase sites publish/list/delete — publishing is a CLI-only operation |
| SDK / HTTP | None — publishing is a build-time step, not something an app calls at runtime |
A publish is an S3 sync against the project's sites bucket (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.htmlif present. - HTML is served
no-cacheso 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 under Observability → Websites.
The <ref>.shovelbase.com URL is for sites that don't have a custom domain yet. On this page, type a subdomain (or leave it blank for the apex) next to a site to put it on a connected domain — see Domains.
Public APIs
A sub-tab of this page, not a separate section: it puts an HTTPS custom domain in front of the project API, giving your apps a SHOVELBASE_URL like https://api.example.com (needed for things like Google OAuth). Caching is disabled there; all methods pass through. See Domains for how attaching a domain works.