Single-Page Apps vs Server-Rendered Web Apps

Jan 19, 2026

The biggest mistake the web made in the last decade was forgetting what it was good at. The web was designed to deliver documents. Click a link, get a page. Submit a form, get a new page. That simple model gave us caching, accessibility, SEO, and performance for free. It scaled to billions of users without anyone having to invent a build step.

Then JavaScript frameworks decided the web was broken. Single-Page Applications promised a future where everything felt like a native app. No page reloads. No waiting. Just smooth, reactive interfaces. And for certain kinds of software — dashboards, collaborative tools, design apps — that promise was real. When you’re inside Figma, Google Docs, or a trading platform, you want instant updates and rich interaction. SPAs shine there.

But somewhere along the way, people started building blogs, marketing sites, and simple CRUD apps as if they were video games. A link that should have been a hyperlink became a router event. A page that should have been HTML became a bundle of JavaScript that had to boot up before showing anything. A user clicking “Back” was suddenly navigating a virtual history stack inside a JavaScript runtime.

We traded reliability for cleverness. Server-rendered apps — whether in Rails, Django, PHP, or modern Next.js SSR — do something radical: they send the user a page. Not a shell. Not a promise. A page. The browser knows what to do with it. Caches can store it. Search engines can read it. Screen readers can interpret it. Even when JavaScript fails, something still appears.

SPAs, by contrast, treat the browser like a dumb terminal. They assume JavaScript will always load, APIs will always respond, and state will always be consistent. When any of that fails, you get blank screens, half-rendered UI, and impossible-to-debug race conditions. This doesn’t mean SPAs are bad. It means they are specialized. A customer-facing SaaS app with complex interactions probably needs a SPA. A public website, onboarding flow, or content-driven app probably doesn’t.

What happened is that tools got good at building SPAs, so people started using them everywhere. When React made component-based UI easy, everything became a component — even things that were never meant to be interactive. A link became a React component. A form became a state machine. A page became a virtual tree. And with that came enormous hidden cost. Build pipelines. Hydration bugs. SEO hacks. Performance tuning. Infinite layers of abstraction to recreate what browsers already did well.

The backlash you see now — toward server-side rendering, partial hydration, and “HTML first” frameworks — is not nostalgia. It’s people rediscovering physics. You cannot beat sending less JavaScript over the wire. You cannot beat letting the browser do what it was built to do. Modern tools like Next.js, Remix, and Astro exist because the industry is trying to walk back from the edge. They acknowledge that JavaScript is powerful but dangerous. They let you sprinkle interactivity instead of drowning in it.

The real answer isn’t SPA or SSR. It’s appropriate complexity. Interactive software should be interactive. Documents should be documents. When everything becomes an app, nothing is reliable. The web doesn’t need to be reinvented. It needs to be respected.