Why I Removed Astro From My Stack (Again)

How Astro's "content-first" defaults taught me that fast metrics aren't the same as respectful user experience — and why TanStack Start is now my one-stack solution.

7 min read
AstroTanStack StartFramework ComparisonWeb DevelopmentUser ExperienceDocumentation UX

How Astro's defaults showed me that "content-first" and "user-experience-first" are not the same thing — 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.

And in doing so, I shipped sites that felt broken the moment someone tried to use them like real people do.

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 WordPress — shiny on metrics, disruptive on usage.

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.

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.

The Docs Red Flag

I should have noticed sooner.

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

The creators — who could add

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

They choose refreshes for their own learning resource.

That tells you everything.

"Zero JS by default" isn't a technical choice. It's a philosophical one so rigid they're willing to degrade their own readers' experience to uphold it.

If they won't make reading about Astro smooth, why trust them to make reading your content smooth?

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.

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

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 defaults/metrics?

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

  • The video keeps playing
  • Form data survives
  • Sidebar stays open
  • Site feels built for humans in 2026

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.

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.

Because my projects need more than that.
They need sites that disappear so content shines.

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.

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.

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.

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

One stack. One model. Defaults that serve users first.

TanStack Start for everything.

Because "content-first" and "user-first" are not synonyms.

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 the person trying to learn without losing their place?

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.


© 2026 Sakhile Dumisa. All rights reserved.