Skip to main content

Specifying HTTP Headers

The headers section allows you to specify custom HTTP response headers for specific resources. The keys in the headers object are the exact paths of the resources (no wildcards), and the values are lists of key-value pairs corresponding to the headers that the portal attaches to the response.

This mechanism allows you to control various aspects of the resource delivery, such as caching, encoding, and content types.

{
"headers": {
"/index.html": {
"Content-Type": "text/html; charset=utf-8",
"Cache-Control": "max-age=3500"
},
"/assets/index.a1b2c3d4.js": {
"Content-Type": "application/javascript; charset=utf-8",
"Cache-Control": "max-age=31536000, immutable"
},
"/assets/index.e5f6a7b8.css": {
"Content-Type": "text/css; charset=utf-8",
"Cache-Control": "max-age=31536000, immutable"
},
"/downloads/report.pdf": {
"Content-Type": "application/pdf",
"Content-Disposition": "attachment; filename=\"report.pdf\""
}
}
}

In the example ws-resources.json, the file index.html is served with the Content-Type header set to text/html; charset=utf-8 and the Cache-Control header set to max-age=3500. The resource path is always represented as starting from the root /.

Defaults

By default, you do not need to specify any headers. The site-builder automatically tries to infer the Content-Type header based on the file extension, and sets the Content-Encoding to identity (no transformation).

If the content type cannot be inferred, the Content-Type is set to application/octet-stream. Any headers specified in the ws-resources.json file will override these defaults.

Content-Type

Set the Content-Type explicitly when the inferred type is incorrect, when you need to specify a charset, or when serving a file type the portal does not recognise.

"/feed.xml":      { "Content-Type": "application/rss+xml; charset=utf-8" }
"/app.wasm": { "Content-Type": "application/wasm" }
"/fonts/x.woff2": { "Content-Type": "font/woff2" }
"/data.csv": { "Content-Type": "text/csv; charset=utf-8" }

For raw markdown files served for LLM ingestion, use lowercase content-type.

Cache-Control

Walrus blobs are immutable, so assets with build-hashed filenames can be cached forever. Entry points should never be cached.

"/index.html":              { "Cache-Control": "no-cache" }
"/assets/app.a1b2c3d4.js": { "Cache-Control": "max-age=31536000, immutable" }
"/assets/style.e5f6a7b8.css": { "Cache-Control": "max-age=31536000, immutable" }
"/data/prices.json": { "Cache-Control": "max-age=300" }
ValueMeaning
no-cacheRevalidate before each use
no-storeNever cache
max-age=31536000, immutableCache for 1 year (content never changes)
max-age=3600Cache for 1 hour

Content-Disposition

Controls whether the browser renders a resource inline or downloads it.

"/docs/guide.md":    { "Content-Disposition": "inline" }
"/whitepaper.pdf": { "Content-Disposition": "inline" }
"/exports/data.csv": { "Content-Disposition": "attachment; filename=\"data-export.csv\"" }

Content-Encoding

Use when serving pre-compressed assets from your build pipeline.

"/assets/app.js.gz": {
"Content-Type": "application/javascript; charset=utf-8",
"Content-Encoding": "gzip"
},
"/assets/styles.css.br": {
"Content-Type": "text/css; charset=utf-8",
"Content-Encoding": "br"
}