Skip to main content

Specifying HTTP Headers

The headers section of ws-resources.json sets custom HTTP response headers for individual resources on your Walrus Site. Each key in the headers object is the exact path of a resource, always starting from the root /. Each value is an object that maps header names to the values the portal attaches to the response. Values must be full names, no wildcard characters are supported.

Custom headers let you control how browsers and other clients handle each resource, for example caching, encoding, content types, and download behavior.

{
"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 this example, the portal serves index.html with the Content-Type header set to text/html; charset=utf-8 and the Cache-Control header set to max-age=3500.

How the portal applies headers

Headers live onchain, not in a server configuration file:

  1. You define the headers in ws-resources.json.
  2. When you run site-builder deploy, the tool writes the headers into your site's resource entries on Sui, alongside each resource path and blob ID.
  3. When a visitor requests a resource, the portal reads the headers from the Sui object and attaches them to the HTTP response.

Because the headers live on Sui, editing ws-resources.json alone changes nothing on your live site. Run site-builder deploy again to apply the new headers.

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 site-builder cannot infer the content type, it sets the Content-Type to application/octet-stream. Headers you specify in the ws-resources.json file 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 you serve a file type the site-builder does not recognize.

"/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 browsers can safely cache assets with build-hashed filenames forever. Do not let browsers cache entry points such as /index.html, because their content changes on every deployment while their paths stay the same.

"/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

The Content-Disposition header controls whether the browser renders a resource inline or downloads it as a file.

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

Content-Encoding

Set Content-Encoding when you serve pre-compressed assets from your build pipeline, so browsers decompress them correctly.

"/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"
}