Rails Frontend in 2025: The Complete Landscape
December 05, 2025
·By GGG
The Rails frontend story has transformed dramatically over the past few years. Gone are the days when your only options were jQuery sprinkles or a full React rebuild. In 2025, Rails offers a sophisticated toolkit that lets you pick the right tool for each job—from server-rendered HTML to full SPAs—all while keeping the Rails conventions you know.
Here’s everything you need to know about building modern frontends with Rails.
The Default Stack: Hotwire
Hotwire (HTML Over The Wire) is the default frontend framework for new Rails applications. It consists of three main components:
Turbo Drive intercepts link clicks and form submissions, making them AJAX requests that replace the page body without a full reload. You get SPA-like speed without writing JavaScript.
Turbo Frames let you define regions of the page that can be updated independently. Wrap a section in a <turbo-frame> tag, and clicks within that frame only update that frame.
Turbo Streams handle real-time updates via WebSockets or server responses, letting you append, prepend, replace, or remove DOM elements from anywhere.
Stimulus is a modest JavaScript framework for adding behaviour to HTML. Rather than taking over your entire frontend, it attaches controllers to existing elements via data attributes.
Rails 8 ships with Turbo 8, which introduces morphing—smarter DOM diffing that smooths out page refreshes with less flicker and fewer Stimulus controller disconnects. Combined with the new Hotwire Native for iOS and Android, you can wrap your Rails app in native shells while keeping server-rendered HTML.
The pitch is compelling: build SPA-like experiences without maintaining a separate frontend application, API layer, or learning React’s state management patterns.
When Hotwire Works Brilliantly
Hotwire excels at:
- CRUD interfaces and admin panels
- Forms with inline validation feedback
- Real-time features (chat, notifications, live updates)
- Progressive enhancement of server-rendered pages
- Apps where most interactivity is request-response based
The 37signals team runs Basecamp and HEY entirely on Hotwire. Many Rails developers report building features in hours that would take days with a React SPA approach—particularly when the alternative involves building both an API and a client-side data layer.
A developer on Hey.com described building a drag-and-drop app in under 500 lines that took a friend’s team 2,000+ lines in React just for the frontend.
When Hotwire Falls Short
Hotwire isn’t universally applicable. Teams have reported friction when:
- Building highly interactive interfaces with complex client-side state
- Implementing features that require optimistic updates and offline support
- Working with third-party JavaScript libraries designed for React/Vue
- Building applications that need to share components with React Native mobile apps
One team’s candid retrospective after 18 months with Hotwire on a 50,000+ DAU SaaS highlights the challenges: complex UI state management becomes awkward, and some interactions that are trivial in React require creative workarounds with Turbo Frames.
The takeaway isn’t that Hotwire is bad—it’s that you need to understand what you’re building before committing to any approach.
JavaScript Bundling Options
Rails offers multiple approaches for handling JavaScript:
Import Maps (Default)
Import maps are the default for new Rails 7+ apps. They let browsers load ES modules directly from URLs without a build step.
Pros:
- Zero build step, no Node.js required
- Instant feedback during development
- Simpler deployment pipeline
Cons:
- No tree-shaking or dead code elimination
- Some npm packages don’t work without transpilation
- No TypeScript support without additional setup
- Your JavaScript source is visible in production
Import maps work well for apps with minimal JavaScript—Stimulus controllers and Turbo, essentially. If you’re staying within Rails’ defaults, they’re excellent.
esbuild (via jsbundling-rails)
esbuild is blazingly fast (written in Go) and handles most bundling needs. It’s the recommended choice when you outgrow import maps.
rails new myapp -j esbuild
Pros:
- Extremely fast builds
- TypeScript support
- npm package compatibility
- Tree-shaking and minification
Cons:
- Requires Node.js in your deployment pipeline
- Some advanced features (code splitting, CSS handling) are limited
For most Rails apps that need more than import maps, esbuild hits the sweet spot of speed and capability.
Vite (via vite_ruby)
Vite uses esbuild for development and Rollup for production builds, giving you the best of both worlds.
Pros:
- Lightning-fast HMR (Hot Module Replacement)
- Mature production optimisation via Rollup
- React/Vue plugin ecosystem
- Better CSS handling than esbuild alone
Cons:
- Additional complexity over esbuild
- Heavier setup
Vite makes sense if you’re building a more JavaScript-heavy frontend or using Inertia.js with React/Vue.
Bun
Bun is the newest contender—an all-in-one JavaScript runtime that includes a bundler, transpiler, and package manager. Some benchmarks show it 3x faster than esbuild.
It’s still maturing for Rails integration, but worth watching if you want bleeding-edge performance.
CSS: Tailwind is King
Tailwind CSS has become the dominant styling approach in the Rails ecosystem. Rails makes setup trivial:
rails new myapp --css tailwind
The tailwindcss-rails gem includes a standalone Tailwind CLI—no Node.js required. Tailwind v4 simplified configuration further by moving everything into your main CSS file.
Why Tailwind dominates:
- Utility classes eliminate context-switching between HTML and CSS files
- PurgeCSS removes unused styles automatically
- The constraint-based design system promotes consistency
- Copy-paste component libraries like Flowbite and daisyUI accelerate development
If you prefer traditional CSS or another framework, Rails supports Bootstrap, Bulma, and others via cssbundling-rails. But Tailwind’s momentum in the Rails community is undeniable.
Component Libraries: ViewComponent vs Phlex
As Rails applications grow, ERB partials become unwieldy. Two libraries offer better abstractions:
ViewComponent
ViewComponent, created by GitHub, brings component-based architecture to Rails views. Components are Ruby classes with associated ERB templates.
# app/components/message_component.rb
class MessageComponent < ViewComponent::Base
def initialize(name:)
@name = name
end
end
<%# app/components/message_component.html.erb %>
<h1>Hello, <%= @name %>!</h1>
Pros:
- Familiar ERB syntax
- Explicit interfaces (no more implicit instance variables)
- Unit testable (100x faster than controller tests)
- Sidecar files keep related assets together
Cons:
- Multiple files per component
- Now in long-term support (feature-complete, no major new features)
Phlex
Phlex takes a different approach: write HTML in pure Ruby.
class Nav < Phlex::HTML
def template
nav(class: "main-nav") do
ul do
li { a(href: "/") { "Home" } }
li { a(href: "/about") { "About" } }
end
end
end
end
Pros:
- Single file per component
- Full Ruby refactoring tools work on views
- Built-in XSS protection
- Fragment caching and streaming support
Cons:
- Learning curve if you’re used to templates
- Smaller ecosystem than ViewComponent
- Copy-pasting HTML examples requires conversion
Both work well with Tailwind, Stimulus, and Turbo. ViewComponent feels more familiar; Phlex feels more powerful once you’re comfortable. RubyUI provides a Phlex-based component library if you want pre-built components.
The SPA Alternative: Inertia.js
Inertia.js offers a middle path between Hotwire and a full SPA. It lets you use React, Vue, or Svelte components as your view layer while keeping Rails conventions for routing, controllers, and data fetching.
# app/controllers/posts_controller.rb
def index
render inertia: 'Posts/Index', props: {
posts: Post.all.as_json
}
end
Your React component receives posts as a prop. No API to build, no client-side routing to configure. Inertia handles the protocol.
When to choose Inertia:
- Your team has React/Vue expertise
- You need complex client-side interactivity
- You want to share components with a React Native app
- Specific npm packages only work with React/Vue
When to stick with Hotwire:
- Your team is primarily Ruby developers
- Most pages are standard CRUD
- You want the simplest possible stack
The inertia_rails gem has matured significantly, with generators and good Vite integration. Evil Martians’ guides are excellent for getting started.
The Hybrid Approach
The emerging consensus is that Rails frontends don’t require a single choice. The Evil Martians’ “silver toolbox” approach:
- Hotwire for standard CRUD interfaces, admin panels, and pages where server-side state is king
- Turbo Mount for embedding React/Vue components into Hotwire pages when you need isolated interactivity
- Inertia.js for full SPAs when you need the full power of a frontend framework
Turbo Mount is particularly clever—it lets you mount React, Vue, or Svelte components directly into Turbo-powered pages without converting your entire app to Inertia.
The Developer Experience in 2025
Rails 8’s frontend story is remarkably complete:
- Hot reloading:
hotwire-livereloadgem watches CSS and views, reloading automatically - Type checking: TypeScript works with esbuild or Vite
- Testing: ViewComponent and Phlex components are unit-testable
- IDE support: RubyLSP, Tailwind IntelliSense, and Stimulus LSP improve the editing experience
The tooling has caught up. You’re no longer making significant sacrifices by staying in the Rails ecosystem for frontend work.
Decision Framework
Choose Hotwire if:
- Your team is primarily backend developers
- Most pages are form-based CRUD
- You want the simplest possible setup
- Real-time features matter more than complex client state
Choose Inertia.js if:
- Your team has React/Vue experience
- You need complex client-side interactivity
- You want to share components across web and mobile
- Specific JavaScript libraries require a framework
Choose a hybrid approach if:
- Different parts of your app have different needs
- You want to start with Hotwire and add React where needed
- You’re building a large application with varied requirements
My Take
For most Rails applications in 2025, I’d start with the defaults: Hotwire, Tailwind, and import maps. You can build surprisingly sophisticated UIs without touching React.
When you hit limitations—a complex dashboard, a collaborative editing feature, something that genuinely needs client-side state—reach for Turbo Mount to embed React components, or consider Inertia.js if you’re building multiple such features.
The key insight is that Rails frontend isn’t one size fits all anymore. The ecosystem has matured to offer real choices. Pick the tool that matches your team’s skills and your application’s actual needs, not what’s trending on Twitter.
Published December 2025. The Rails frontend ecosystem continues to evolve rapidly—check gem and library documentation for the latest features.
Further Reading & Resources
Hotwire
- Turbo Documentation
- Stimulus Handbook
- Hotrails Tutorial - Comprehensive Turbo tutorial
- Interactive Rails UIs with Stimulus & Turbo
JavaScript Bundling
CSS
Components
- ViewComponent Documentation
- Phlex
- RubyUI - Phlex Component Library
- Modern Rails Frontend: ERB vs ViewComponent vs Phlex
Inertia.js
Comparisons & Philosophy