Why Turbo? Stop Overcomplicating Your Web Apps

Too many developers are overcomplicating their web apps. They're reaching for React before they have product-market fit. They're setting up Webpack configs for a landing page. They're debugging hydration errors instead of shipping features.

I've watched this pattern play out dozens of times. A founder comes to me with a simple CRUD app—maybe a project management tool or an e-commerce site—and they've already scaffolded a Next.js frontend with a separate API backend. Two codebases. Two deployment pipelines. Two places for bugs to hide. And they haven't launched yet.

Turbo exists because that's insane.

The Problem: Two Bad Options


For the last decade, web developers faced an impossible choice.

Option one: Build a traditional server-rendered app. Rails, Django, Laravel—pick your poison. Simple to build, simple to deploy. But every click reloads the entire page. Users see a white flash. Forms feel sluggish. The whole experience screams "2008."

Option two: Build a single-page app. React, Vue, Angular. Smooth transitions, instant updates, feels like a native app. But now you need a JSON API. A state management library. A build pipeline. Probably 500+ npm packages just to render "Hello World."

Most apps don't need option two. But most developers choose it anyway because option one feels slow. That's the trap.

What Actually Makes SPAs Fast


Here's the thing about single-page apps: they're not fast because of React. They're not fast because of virtual DOM diffing. They're fast because they don't do full page reloads.

When you click a link in a traditional app, the browser throws everything away. It re-downloads the header, the navigation, the footer, re-parses all your JavaScript, re-applies all your CSS. Even if only 5% of the page actually changed.

SPAs intercept that click and fetch just the data. Then they update just what changed. No full reload. That's why they feel fast.

But here's what nobody talks about: there's nothing magical about JSON. You can do the exact same thing with HTML.

Turbo's Big Idea


Turbo intercepts link clicks and form submissions, fetches HTML instead of doing a full page reload, and swaps out the body content. That's it. That's the whole trick.

Your server still renders complete HTML pages. Your templates stay the same. Your routing stays the same. But now clicking links feels instant because there's no white flash, no re-parsing, no starting over.

The best part? You don't change your existing code. Include Turbo, and your entire site is automatically faster. Zero refactoring.

The Numbers


Turbo is about 19KB gzipped. React plus ReactDOM is around 45KB—and that's before you add routing, state management, and whatever else you need to actually build something. Real-world React apps commonly ship 200KB+ of JavaScript. I've seen plenty break 500KB.

But bundle size isn't even the real issue. The real issue is complexity.

A React app means maintaining two codebases. Learning component lifecycles and hooks. Debugging async state bugs. Setting up build tooling. Managing API versioning. Handling client-side routing edge cases.

With Turbo, your Rails app is still just a Rails app. Your Django app is still just a Django app. You write server-side code, you render HTML templates, you ship. The JavaScript complexity disappears.

Turbo Frames: Surgical Updates


What if you only want to update part of the page? That's what Turbo Frames are for.

Wrap any section in a <turbo-frame> tag:

<turbo-frame id="comments">
  <form action="/posts/1/comments" method="post">
    <input name="body" placeholder="Add a comment...">
    <button>Post</button>
  </form>
  
  <div class="comment">Previous comment...</div>
</turbo-frame>

Submit that form, and only the comments frame updates. The rest of the page stays put. Your server returns a full HTML response—Turbo extracts just the matching frame and swaps it in.

No JavaScript. No React components. No state management. Just HTML.

When Turbo Doesn't Make Sense


I'm not going to pretend Turbo is perfect for everything. If you're building Figma, you need client-side rendering. If you're building a real-time multiplayer game, you need client-side state. If you're building an app that works completely offline, you need a different architecture.

But those apps are maybe 5% of what gets built. The other 95%—blogs, e-commerce sites, dashboards, admin panels, CRUD apps, project management tools—are exactly what Turbo was designed for.

The honest question every developer should ask: Does my app actually need client-side rendering, or am I just used to reaching for React?

The Hotwire Philosophy


Turbo is part of Hotwire, which stands for HTML Over The Wire. It comes from 37signals—the team behind Basecamp and Hey. They've been shipping fast, interactive web apps without heavy JavaScript frameworks for years.

The philosophy is simple: send HTML, not JSON. Let the server do the heavy lifting. Use JavaScript to sprinkle interactivity, not to build your entire UI.

This isn't about being anti-JavaScript. It's about using the right tool for the job. And for most web apps, the right tool is a lot simpler than we've been told.

Start Simple


If you're starting a new project, try this: build it with Rails and Turbo. Or Django and Turbo. Or Laravel and Turbo. Ship it. Talk to users. Iterate.

You can always add more JavaScript later if you need it. But you probably won't.

I've built apps that handle thousands of concurrent users with nothing but server-rendered HTML and Turbo. No React. No Vue. No webpack. Just clean, simple code that's easy to understand, easy to debug, and easy to ship.

That's the goal, isn't it? Ship often. Ship fast. Build something people actually use.

Turbo lets you do that without the complexity tax.