Why not write logic in Astro layouts
By Flavio Copes
Why you should not put logic in Astro layouts: you cannot call Astro.redirect() there since the response is already sent, so keep that logic in your pages.
Short answer: because by the time a layout runs, Astro has already started sending the response to the client. Anything that needs to change that response, like a redirect, fails.
I learned this the hard way.
I wrote in Astro page layout and middleware execution order how I moved some logic to a layout.
Had to roll back because turns out I couldn’t run Astro.redirect() in a layout, since Astro tells me the response has already been sent to the client.
Turns out this was something I absolutely needed, so moved back to handling the logic in the pages, which was ultimately the right thing from the start.
Why the layout felt tempting
The temptation is real. Say you have ten pages behind a login, all using the same layout. Doing the auth check once in the layout looks like the obvious deduplication:
---
// src/layouts/DashboardLayout.astro
const session = Astro.cookies.get('session')
if (!session) {
return Astro.redirect('/login')
}
---
<html>
<body>
<slot />
</body>
</html>
One check, ten pages protected. Except it doesn’t work.
The page renders first, and the layout is just a component the page renders into. When the layout frontmatter runs, the response is already on its way out. Too late to swap it for a redirect.
What works instead
The check goes in each page, before any rendering happens:
---
// src/pages/dashboard.astro
import DashboardLayout from '../layouts/DashboardLayout.astro'
const session = Astro.cookies.get('session')
if (!session) {
return Astro.redirect('/login')
}
---
<DashboardLayout>
<h1>Dashboard</h1>
</DashboardLayout>
Yes, it’s repeated across pages. But the page owns the response, so it’s the one place where a redirect is guaranteed to work.
The bigger lesson for me: layouts are for markup. The shared <head>, the header, the footer, the wrapper around a <slot />. The moment I put decisions about the response in there, I’m fighting how Astro works.
It also makes pages easier to read. Open dashboard.astro and the auth requirement is right there at the top, not hidden two files away in a layout.
Discovering new things each and every day.
Related posts about astro: