Why I Removed Astro From My Stack: A Regression in Disguise

Astro's 'content-first' defaults ignore why routing was invented. Fast metrics aren't the same as respectful user experience — and TanStack Start brings me back to the present.

Sakhile Dumisa
Sakhile Dumisa
·8 min read

How Astro's default full-page refreshes taught me that "content-first" ignores a problem we solved 15 years ago — and why I'm consolidating to TanStack Start for everything.

A few days ago, I wrote about adding Astro to my stack. I was excited. The promise was clean: Astro for content, TanStack Start for apps, Hono for APIs. Each tool in its lane.

I was wrong.

Not about Astro being excellent at static content — it is.
I was wrong about what "content-first" really delivers when users start navigating.

I confused developer convenience with reader comfort.
I confused Lighthouse scores with actual human flow.

But more than that, I forgot a fundamental lesson of web history: routing was invented because full-page refreshes are a bad user experience. And Astro's default is to pretend that problem doesn't exist.

The Crack That Broke It

It started innocently. A client portfolio in Astro. Stunning first load. 100 Lighthouse. Everyone congratulated me.

Then I used it — not as the builder, but as a visitor.

Clicking to compare projects. Trying to keep a demo video playing while scanning details.
Every click: full page refresh.

Video stops.
Sidebar scroll resets.
Any in-page state: gone.

It felt like 2005. It felt like the web I'd fought to escape. It felt like a regression.

A Brief History We Forgot

Routing wasn't invented to make SPAs complex. It was invented to solve a real user problem:

  1. Navigation is good. The user wants to move to a new view.
  2. Refreshing is bad. It destroys context, interrupts playback, and resets state.
  3. Conditional rendering (hide/show divs) wasn't the answer. It breaks the URL, the back button, and deep linking.

We created routers to get the best of both worlds: new content, no refresh, intact state, and a functioning URL. Every major framework adopted this as the baseline for a respectful user experience in the 2010s.

Astro, in 2026, defaults to the pre-routing era.

What Metrics Hide

Astro sells "zero JS by default" as performance victory. And it is — for the very first visit.

But here's what no score tells you:

MetricWhat It MeasuresWhat It Completely Ignores
First Contentful PaintInitial page arrivalThe next 20 internal clicks
Cumulative Layout ShiftFirst-load stabilityEvery reload flicker after that
Performance ScoreLab data on empty cacheReal-user frustration on repeated navigation

My sites scored perfect.
My users still had a worse experience than any SPA I'd built before.

Because performance isn't only speed — it's continuity.

The SessionStorage Wake-Up Call

The real break came with form data loss.

A simple multi-step quote form across pages. Nothing fancy.
Built with Astro + React islands. "JS only where needed," right?

User goes step 1 → step 2.
SessionStorage wiped. Form progress gone.

This isn't a bug. It's how full-page refreshes work: new browsing context, new session.
Temporary state? Erased.

I wasted days on workarounds:

  • localStorage (persists forever, wrong scope)
  • URL params (ugly, limited length)
  • Server sessions (overkill for client flow)

All to fight the framework's default navigation model. A model that ignores that we solved state persistence with routing over a decade ago.

The Layout Illusion

Astro has "layouts." You wrap pages in headers, sidebars, footers. Looks modern.

It's an illusion.

In TanStack Start (or any router-first framework), layouts persist. Header mounts once. Sidebar keeps scroll. Outlet swaps only content.

In Astro, layouts are templates. Every navigation: full re-render.
Header remounts. Sidebar collapses. Video restarts. Console clears.

Layouts without persistence are just fancy includes. They are not an evolution; they are a step backward to server-side includes from the 1990s.

The Docs Red Flag

I should have noticed sooner.

Astro's own documentation uses full-page refreshes between articles.

The creators — who could add

<ClientRouter />
+ persistence in one line — choose not to.

They choose refreshes for their own learning resource.

That tells you everything. If the framework's own documentation doesn't respect the reader's continuity, why would yours?

The Incentives Layer

Full refreshes = new request per navigation.
New request = edge hit.
Edge hits = metrics Cloudflare loves.

Cloudflare acquired Astro (early 2026).
Astro loves Cloudflare.
Both thrive on MPA patterns where every click generates cacheable traffic.

Not conspiracy. Just aligned incentives.

And those incentives favor full refreshes over persistent continuity. They favor a 2005-era technical model because it serves the infrastructure provider, not the user.

My users pay the price.

The Updated Reality Check

Revisiting the table from last time — with honesty:

AspectTanStack StartAstro (default)What Actually Matters
Initial loadSSR + React bundleZero JSAstro wins first paint
Subsequent navigationInstant, no refreshFull refresh, resetTanStack wins every click after
Layouts / OutletsTrue persistenceRe-rendered templatesTanStack keeps continuity
SessionStorage / StateSurvives across routesCleared on navTanStack preserves user progress
Docs / Learning UXSmooth, persistentDisruptive refreshesTanStack respects readers
Mental modelUnified, user-firstContent-firstContent-first ≠ reader-first
History RespectSolves the refresh problemIgnores itTanStack learns from the past

The Question That Mattered

Last time I asked: "Is your content serving the framework?"

Wrong question.

Right one:
Is your framework serving your users, or are your users serving someone's default that ignores 15 years of web progress?

Users don't care about zero JS. They care if:

  • The video keeps playing
  • Form data survives
  • Sidebar stays open
  • The back button works without a full reload
  • Site feels built for humans in 2026, not servers in 2005

Astro defaults fail those tests.

What My Projects Actually Need

Project TypeUser NeedBest Fit
PortfolioSmooth browsing, compare without resetsPersistent routing
Blog / DocsRead without losing place/contextNo refreshes
MarketingFluid explorationContinuity
Client toolsKeep state across stepsTrue layouts

These aren't "app-only" needs. They're basic 2026 expectations built on lessons we learned from the early 2000s.

The Performance Myth Revisited

"But SPAs ship too much JS!"

Thoughtless SPAs do.
TanStack Start doesn't:

  • Code-splitting by route
  • Lean router core
  • Isomorphic loaders (server/client, no duplication)
  • Streaming SSR when needed

I can build fast + persistent.
Astro forces me to choose fast or persistent.

The Consolidation

I'm removing Astro.

Not because it's useless — it's exceptional for pure static landing pages where navigation is minimal.

Because my projects need more than that.
They need sites that respect the user's context. They need to use the tools we invented to solve the refresh problem, not pretend that problem is a virtue.

Now:

  • TanStack Start for everything (SSR/static + persistent routing)
  • Hono for APIs

For content: TanStack's static gen + markdown. Takes setup time.
Worth it for no refreshes, real persistence, respectful UX.

Lessons Hard-Won

  1. Developer DX ≠ user UX. My quick setup doesn't matter if readers fight refreshes.
  2. Zero JS is a metric, not morality. A blank page loads fast. That's not victory.
  3. Layouts that remount aren't layouts. They're templates.
  4. Docs are the ultimate test. If a framework won't smooth its own docs, they're showing priorities.
  5. Incentives shape defaults. Follow them — and see who benefits.
  6. Routing was invented for a reason. Ignoring that reason isn't "content-first." It's history-blind.

Objections I Would Have Made (And Why They Don't Hold)

"Add View Transitions!"
Astro could default it for docs. They don't. Defaults reveal truth.

"Content sites don't need state!"
Scroll position is state. Open accordions are state. Form progress is state. Readers notice when lost.

"But it's MPA by design!"
Exactly. And MPA defaults are disrespectful for learning content in 2026. They ignore why we built better patterns.

Conclusion

I was wrong last time. Not about Astro's tech — about what matters most.

What matters is continuity. Respecting that users build mental context while navigating. Making tech invisible so content breathes.

Astro defaults make tech visible — painfully — with every refresh. They pretend that the problem of the full-page refresh, solved by routing, doesn't exist.

TanStack Start makes tech disappear.
That's the win.

One stack. One model. Defaults that serve users first and respect the history of our craft.

TanStack Start for everything.

Because "content-first" and "user-first" are not synonyms. And because ignoring the lessons of the past is a sure way to repeat its mistakes.

And I choose users.


If you're eyeing Astro for docs, blogs, or anything navigable: ask who you're really optimizing for. Your bundle size? Or are you ignoring 15 years of web progress?

Update March 15, 2026: This replaces my earlier Astro recommendation. Real usage changed my mind. Your mileage may vary — but my readers' experience didn't.