Thick walls, thin walls
Two recent personal projects, two different stacks, one decision rule. Framework choice is downstream of the workload's interactivity profile, not personal taste.
I shipped two projects in the same window. Sumo App is built on Next.js 16. Murako is built on Astro. People ask why — both could in theory live on either stack.
The short answer: framework choice is downstream of the page’s interactivity profile, not personal taste. The longer answer is below.
Sumo App — thick walls earn their keep
Sumo App is a live tournament tracker. It has:
- A real-time SSE pipe pushing match updates from upstream
- A TanStack Query cache hydrated by both the initial fetch and the SSE stream
- A build-time pipeline of generated illustrations (FLUX.1 + IP-Adapter)
- Per-request edge logic for the SSE proxy
- Server-rendered wrestler profile pages so SEO and OG previews work for ~200 dynamic surfaces
The framework is doing real work on every request. RSC, edge runtime, streaming — load-bearing, not decorative. Hydration cost is paid for by the interactivity it enables.
Could I have built this on Astro? Technically. I’d have to reinvent the SSE proxy, hand-roll the server-cache primitive that TanStack Query already gives me, and fight Astro’s static-first defaults the entire way. That’s not a framework fit; that’s a framework cage match.
Murako — thin walls do less, deliberately
Murako is the editorial site for an architecture studio. It has:
- ~95% of pages output once and served forever
- A Keystatic Cloud editorial workflow for the studio
- One contact form gated by Cloudflare Turnstile and forwarded by Resend
- Zero real-time anything
Astro’s islands model means the framework cost-per-page approaches zero on the static pages. JS only ships where there’s actual interactivity (the contact form). Build is fast, Lighthouse is green without trying, the CMS workflow is editorial-friendly.
Could I have built this on Next.js? Yes. I’d burn build time on hundreds of statically-rendered pages, ship more JS than the user needs, and pay a hydration tax on a marketing site whose interactivity surface is one form. The framework would be doing nothing that justifies its weight.
The trap to name
Most teams make this decision once and then force the framework onto every workload. “We’re a Next shop” / “we’re an Astro shop”. That’s an org choice, not a technical one — and it’s fine, with eyes open.
What’s not fine is the version I see most often: companies eager to vendor-lock themselves to a single framework and reuse it on every project, regardless of fit. I’ve been asked, more than once, to build “the new project template” — the implicit goal being that nobody ever has to make the framework decision again. A new project starts from the same Next.js boilerplate because the last one did. Domain-heavy product? Next. Small client-side dashboard with no SEO and no SSR? Also Next. Static marketing site? Same boilerplate, fewer pages.
The framework becomes corporate furniture — comfortable, defaults to the same shape, and quietly inappropriate for a fair share of the workloads it covers.
The cost lands on developers, not on leadership. Hydration on pages that don’t need it. Build pipelines doing work no user benefits from. Junior engineers learning one framework’s mental model so deeply that any other choice feels foreign. The default ossifies; the team’s range narrows with it. Development slows because every problem now has to be reshaped to fit the boilerplate, instead of the boilerplate being chosen to fit the problem.
The architect’s job is to name the moment when a project’s interactivity profile doesn’t match the org’s default framework, and to either make the case for switching or design around the mismatch deliberately. Picking the comfortable option silently is the cheapest way to ship a year of unnecessary complexity.
A true developer uses the best tools for the job, not their favourite ones. The org-default-template is the favourite tool wearing a name tag.
Hindsight
Six months in. Sumo App’s bundle size and TTFB look right for what it does. Murako is at the lower bound of what’s possible — most pages transfer under 30KB, all of it cached at the edge.
If I’d swapped them, both would still work. Both would also be measurably worse, in opposite directions. Sumo on Astro would be fighting hydration boundaries every time a new dynamic surface landed; Murako on Next would be paying a hydration tax for a contact form.
The rule that survived: frameworks aren’t interchangeable; they’re different shapes of “what’s free vs what costs”. Astro makes static cheap and interactivity manual. Next makes interactivity cheap and static automatic-but-expensive. Match the shape to the workload.
The corollary: I don’t have a favourite framework. I have a favourite fit. Anyone hiring an architect for the framework they prefer is hiring for taste, not judgment.