Headers

Response headers go in a _headers file at the root of the deploy. The format is a subset of the one Netlify and Cloudflare Pages read.

The default headers

Every response carries these three, except a redirect of a whole hostname to the canonical domain, which carries only Location:

HTML (an extensionless path, .html or .htm) is served with Cache-Control: public, max-age=600, and everything else with public, max-age=86400. Your files also carry ETag and Last-Modified, so a returning browser can revalidate and get a 304, and range requests are supported.

_headers can override or drop the three default headers, and override Cache-Control, on the paths you choose. Two things stay as they are. The Kamakiri not-found page always carries the default set. Every 4xx and 5xx response is served no-store, whatever Cache-Control a block sets; redirects stay cacheable.

There is no Strict-Transport-Security, and you cannot add one.

The file

A _headers file is a series of blocks. A block is a path line, starting with / and not indented, followed by indented header lines.

# a full-line comment starts with #
/path/*
  X-Custom-Header: value
  Cache-Control: public, max-age=3600
  ! X-Frame-Options

Only a file named exactly _headers at the root of the deploy is read as headers, and it is not served. A _Headers, or a sub/_headers, is served as an ordinary file.

Blocks

A header you set replaces the default of the same name on the block’s paths only. Other paths keep the default.

What is rejected

A rejected line fails the whole deploy with a line-numbered error. When you deploy a directory, kamakiri deploy checks the file before uploading anything. An archive is checked by the service after the upload. Either way, the live site does not change.

What is dropped

These names are dropped rather than rejected, so a file from Netlify or Cloudflare Pages still deploys. When you deploy a directory, kamakiri deploy prints a warning for each dropped line and carries on. From an archive, the lines are dropped without a warning.

Limits

A file over any of these is rejected, not truncated.

Portability

Blocks of Name: value lines under an exact path, /*, or a prefix such as /assets/* behave the same on Kamakiri, Netlify and Cloudflare Pages. Netlify ignores ! Name, so a file that drops headers ports to Cloudflare Pages only. A file from either platform that uses a :placeholder or any other * is rejected here.

Examples

# A custom header on every response
/*
  X-Custom-Header: hello

# Long-lived caching for hashed assets (one comma-separated line)
/assets/*
  Cache-Control: public, max-age=31536000, immutable

# Override a default site-wide
/*
  Referrer-Policy: no-referrer

# Drop a default for one path only; other paths keep X-Frame-Options: DENY
/embed/*
  ! X-Frame-Options