Astro, set response header
By Flavio Copes
A quick reference for setting a response header in an Astro component with Astro.response.headers.set, shown here sending an HX-Redirect header.
To set a response header in an Astro component, call Astro.response.headers.set() in the frontmatter:
Astro.response.headers.set('HX-Redirect', '/login')
Astro.response represents the response Astro is about to send back to the browser. Its headers property is a standard Headers object, so you also get append(), get() and delete().
Why would you set a header?
The HX-Redirect example comes from a real project. With htmx, requests happen via AJAX, so a normal redirect would swap the login page into a small part of the current page. Sending the HX-Redirect header tells htmx to perform a full browser redirect to /login instead.
Caching is another common reason:
Astro.response.headers.set('Cache-Control', 'max-age=3600')
Security headers and custom debugging headers work the same way. Anything the HTTP response should carry.
This needs server-side rendering
Here’s the pitfall. Headers exist at request time. If the page is prerendered, Astro builds a static HTML file once, and no code runs when someone requests it. Your Astro.response.headers.set() call runs at build time, and the header goes nowhere.
The fix is to render the page on demand:
export const prerender = false
This requires an adapter (Node, Vercel, Cloudflare…) so Astro has a server to run your code on. If your whole site uses output: 'server', pages are already rendered on demand and you can skip this.
Set headers before the body streams
Astro streams the HTML response as it renders. Headers go out first. If you call Astro.response.headers.set() inside a component rendered deep down the page, the headers may already be on their way, and your change won’t reach the browser.
My advice: set response headers in the frontmatter of the page itself, right at the top of the request. Not in nested components.
You can also change the status
Astro.response covers more than headers:
Astro.response.status = 404
Astro.response.statusText = 'Not found'
Same rules apply: on-demand rendering only, and set it before the response starts streaming.
Related posts about astro: