Skip to content

What a website serves

File types, addresses, app routing, caching, headers, and what browser storage can be trusted with.

File types

A website can contain these file types. Each file is served with the type its extension names here, never a type guessed from its contents; a deploy with any other extension is refused and names the file.

KindExtensions
Pages and datahtml, txt, xml, json, webmanifest, pdf
Styles and scriptscss, js, mjs, map, wasm
Imagessvg, png, jpg, jpeg, gif, webp, avif, ico
Fontswoff, woff2, ttf, otf
Audio and videomp4, webm, mp3, wav
  • A path is at most 256 bytes, with no empty, . or .. parts, and no hidden file or folder except a top-level .well-known.
  • PDFs download rather than open in the browser.
  • A site with no favicon.ico gets Benchy’s. Add your own to replace it.
  • Sizes and file counts are limited per deploy. See Deploy limits.

Addresses and pages

Benchy finds the file for an address in this order:

AddressServes
//index.html
/about//about/index.html
/aboutThe file /about; else a redirect to /about/ when /about/index.html exists; else /about.html
Anything elseYour /404.html with status 404, or Benchy’s “Page not found”

The redirect to /about/ keeps the query string, and it is what makes relative links inside about/index.html work.

App routing

A single-page app that routes in the browser, with addresses such as /products/42, needs every such address to load its index.html. Say so in a benchy.site.json file at the top of the output folder:

benchy.site.json
{
  "fallback": "/index.html"
}
  • An address with no file and no extension then serves /index.html with status 200. An address with an extension, such as /app.js, still gets a 404 when the file is missing, so a broken script shows as broken.
  • Real files and folders always win over the fallback.
  • benchy.site.json is read when you deploy and is not served. It also declares content and forms; see Content and forms.

JavaScript, apps and backends

JavaScript and WebAssembly run in your visitors’ browsers, so games, tools, 3D viewers and other browser apps work. What a website doesn’t have is a server of its own:

  • no server functions, API routes or server-side rendering;
  • no database, and no visitor sign-in;
  • no secrets. Every file is public, so an API key in a published file is a leaked key.

When a site needs a backend, the browser calls one you run elsewhere, such as Convex, Supabase or your own API. Benchy provides two server features itself, both on your site’s own address: editable content and forms. The path /_benchy/ is reserved for them on every site.

Caching

FilesHow long browsers and the CDN keep them
HTML pagesChecked on every visit, so a new version shows at once
Files whose name carries a fingerprint of 8 or more characters, such as app.3f9a1c2b.jsA year. Build tools name files this way, so a change gets a new name
Everything else5 minutes

Every file is sent with its fingerprint as its ETag, so unchanged files cost a visitor nothing to check, and audio and video can be streamed and seeked.

Headers

Benchy sets every response header itself. Every page is sent with:

  • Strict-Transport-Security, so browsers use HTTPS only: two years on benchy.site, one week on a custom domain;
  • X-Content-Type-Options: nosniff and Referrer-Policy: strict-origin-when-cross-origin;
  • Permissions-Policy turning off the camera, microphone and location;
  • frame-ancestors 'self', so only your own site can show your pages in a frame;
  • X-Robots-Tag: noindex when the site is kept out of search. See Search engines.

You can’t add or change headers, and _headers or _redirects files from other hosts do nothing. A Content Security Policy in a <meta http-equiv> tag in your HTML still applies.

Cookies and storage

Benchy never sets a cookie on a website, and Benchy’s own sign-in never reaches one. Every site on benchy.site shares the parent domain benchy.site, so a script on one site can set a cookie that every other site receives.

  • Don’t treat a cookie, localStorage or sessionStorage value as trustworthy. Use them for things a visitor can harmlessly change, such as a remembered theme or a dismissed notice.
  • Don’t set a cookie on the parent domain, and don’t rely on reading one set there.
  • A custom domain gives the site an origin of its own. Write the site so the advice above holds either way.

When a website is unpublished or suspended, visitors’ browsers are asked to clear what it stored.

What a website can’t do

  • Run a service worker. A worker could keep serving a site after it is unpublished, so none are served. Pages still work offline as far as the browser cache allows.
  • Take anything but GET and HEAD. Other requests get 405, except form entries sent to /_benchy/forms/.
  • Redirect or rewrite on the server, beyond the address rules and the app fallback above. Use an HTML page with a <meta http-equiv="refresh"> tag to send visitors from an old address to a new one.
  • Use the camera, microphone or location.

Use ← and → to move between pages.