Skip to content
Stackship documentation Svenska

Static Web AppsUsers

Routing and caching

How a static web app answers requests — the single-page app fallback, the 404 page, the cache presets and their exact headers, redirects and response headers.

All of these settings apply without packaging the site again: a change takes effect within seconds.

How a request is answered

Redirects are checked before these steps.

  1. A path that matches a file serves the file; a path that matches a directory serves the directory's index.html.
  2. Otherwise, with a single-page app fallback set, the fallback file is served with status 200.
  3. Otherwise the answer is 404, with the 404 page when one is set.

Requests for asset files never fall back: a missing .js, .css, image or font file answers 404 instead of the fallback page. Asset files are those ending in .js, .mjs, .css, .woff, .woff2, .ttf, .otf, .eot, .svg, .png, .jpg, .jpeg, .gif, .webp, .avif, .ico or .map.

Single-page app fallback

Where Setting Values
Create wizard Single-page app routing On (the default) serves /index.html; off serves 404
Configuration → Routing Single-page app fallback An absolute path such as /index.html; empty turns the fallback off
API, CLI navigationFallback Same as above
API, CLI navigationFallbackExclude Paths that keep answering 404 instead of falling back, such as /api/*

404 page

404 page (notFoundPage) is an absolute path such as /404.html. It is served, with status 404, for every path that matches no file and does not fall back. Empty serves the web server's own 404 page.

The fallback file and the 404 page must exist in the deployed site. When one does not, the changed routing does not start: the site keeps its previous routing and shows Degraded.

Cache presets

Preset (API value) Hashed asset files Other asset files /index.html Everything else
Hashed assets (recommended) (HashedAssetsImmutable) public, max-age=31536000, immutable none no-cache none
Cache all assets (Aggressive) public, max-age=31536000, immutable public, max-age=31536000, immutable no-cache none
No cache headers (Off) none none none none

The values are the Cache-Control header; "none" means the response carries no Cache-Control header.

  • A hashed asset file has a hash of at least eight letters, digits, _ or - between two dots right before its extension, such as app.4f3c2b1a.js. A hash joined with a hyphen, as in index-4f3c2b1a.js, does not count.
  • max-age=31536000 is one year. Under Cache all assets, returning visitors keep an unhashed file such as logo.png for up to a year, even after you deploy a new one.
  • no-cache makes browsers check with the site before reusing /index.html, so a deployment shows at once. It applies when /index.html is requested directly, for /, and when it is served as the fallback.

Other rules

  • Files and directories whose names begin with a dot are refused, except under /.well-known/.
  • Text responses — HTML, CSS, JavaScript, JSON, XML, SVG, plain text — are compressed with gzip.
  • Plain HTTP is redirected to HTTPS.

Redirects and response headers

The portal does not edit these; set them through the API or with stsh swa update. They apply without a redeploy, like the rest of the routing.

redirects is a list of rules. A from without * matches that one path and wins over every other rule. Among * rules, the longest matching prefix wins, whatever their order in the list.

Field Meaning
from An absolute path; a trailing * matches every path that starts with it
to An absolute path or a full http:// or https:// URL. Addresses starting with // are refused
statusCode 301 (the default), 302, 307 or 308

headers adds a response header to matching paths.

Field Meaning
path An absolute path, a trailing * matching a prefix; /* (the default) matches everything
name The header name: letters, digits and -
value The header value, on one line

Paths may use letters, digits and / . - _ ~ @ :; they may not contain ... Two redirects that match the same paths are refused.

A * redirect does not catch every path under its prefix. Requests for asset files (the extensions in How a request is answered) are served as files, or answer 404, instead of being redirected while Cache all assets or a single-page app fallback is set. With Hashed assets and no fallback, this applies only to hashed asset files; other asset files are redirected. Paths with a segment that begins with a dot are refused rather than redirected.

Caution

A header whose path is anything other than /* is not sent on the pages under that path. It is sent only on asset files under the path — all of them while Cache all assets or a single-page app fallback is set, only hashed ones with Hashed assets and no fallback, none with No cache headers and no fallback — and on the responses of redirects, the fallback file, the 404 page and /index.html when their own path matches it. A header on /admin/*, for example, does not reach /admin/index.html or any other page there. Headers on /* are sent on every response except under /.well-known/; use /* for security headers such as X-Frame-Options or Content-Security-Policy.

bash
stsh swa update my-site -g my-resource-group \
  --set 'redirects=[{"from":"/blog/*","to":"https://blog.example.com/","statusCode":301}]' \
  --set 'headers=[{"path":"/*","name":"X-Frame-Options","value":"DENY"}]'