Svelte on Rails

Combining two beautiful worlds: Rails backend power and Svelte frontend joy.

For most interfaces, Hotwire is already a great choice. But when you need richer frontend interactivity, Svelte becomes the perfect lightweight layer on top of your Rails app.

In this combination, each can play to his strengths.

You will love it!

Installation + optional Showcase

Copy, paste, and run the following commands in your terminal:

1. Create a new Rails app

If you start from scratch:

rails new svelte-on-rails-testapp app --skip-javascript && cd svelte-on-rails-testapp

2. Install svelte-on-rails

bundle add svelte-on-rails
rails g svelte_on_rails:install

The installer is designed to be carefully and safe:

  • it checks prerequisites
  • it uses an isolated sandbox for checking npm dependencies before applying changes to the app.
  • it won’t overwrite existing files without asking

Just follow the prompts.

To models, where you want to use the to_svelte helper, add exposes_to_svelte, for example:

class Book < ApplicationRecord
  exposes_to_svelte
end

3. Install and run the Showcase

rails g svelte_on_rails:showcase

Code Example

View helper:

<%= svelte('components/Stats', user: @user.to_svelte(:login_count, :name) %>

Component:

app/frontend/javascript/components/User.svelte:

<script>
  let { user } = $props();
</script>

<h1>{ user._schema.self.name } { user.name } { user._schema.loginCount.label }: { user.loginCount }</h1>

Output:

<h1>Benutzer Josef Logins: 77</h1>

<!-- 
the #to_svelte helper 
• returns useful meta-data for models and columns
• serializes data
-->

On the server logs, with the «Completed Line»:

17:35:52 web.1  |   [SOR] ...
17:35:52 web.1  |   [SOR] Stats.svelte returned from cache (1.4ms)
17:35:52 web.1  | Completed 200 OK in 43ms ( ... | ... | Svelte: 2 cached, 1 rendered, 3.3ms)
# or
12:36:45 web.1  | Completed 200 OK in 831ms ( ... | ... | SVELTE BUILD FAILED!)
# or
12:36:45 web.1  | Completed 200 OK in 831ms ( ... | ... | Svelte: build, 3 warnings, 3 cached, 786.7ms)
# or
12:35:22 web.1  | Completed 200 OK in 44ms ( ... | ... | Svelte: 3 cached, 2.1ms)

When you see something like «SVELTE BUILD FAILED» you will find a detailed error message with the links to the files.

Before You Build Your First App

  • Check out the Hotwire Svelte Helpers Example App:
    • This set of helpers makes it easy to create dropdowns, tooltips, and modals with Svelte and Stimulus.
    • It includes form helpers for Svelte that interact with the Rails backend.
    • Z-index issues are solved by configurable rendering into a root-level container.
  • Add some global translations:
  • Consider using Svelte components within app/views, just like partials:
  • Testing:
    • For testing we use this Playwright setup.
    • Important: The gem adds the class hydrated to every component after it has finished hydrating. Append it to your selectors so tests don’t interact with a component before its event listeners are attached, for example:
      page.wait_for_selector(".my-component.hydrated .any-button").click
      
    • This aligns to the .stimulus-connected class of @csedl/hotwire-svelte-helpers.
    • Important: The hydrated class is added to the root element of the Svelte component. This is different from the svelte:options tag option,
  • Performance:
    • Add the redis gem to your Gemfile and set use_caching: true in config/svelte_on_rails.yml.
    • Use watch_changes: true in development only.

Why?

Svelte`s reactivity is the missing piece for Rails+Hotwired.

Why was Svelte invented? Watch the Rethinking Reactivity video (especially 5:00–7:10).

Features

  • Server-Side Rendering
  • SSR Server (Default / similar to react_on_rails pro)
  • Fine-grained fragment caching
  • ActiveRecord integration – pass models directly with .to_svelte
  • New in v10 (experimental) optional support for placing .svelte components directly in app/views
  • Plays nicely with Hotwire Turbo (option: SSR only for initial page load)
  • Fully integrated with rails assets:precompile
  • Built-in interface for server → client communication via ActionCable / Turbo Streams
  • Fully configurable
  • Detailled logging for performance optimization and error detection

Enjoy it! 😉

For Questions or Issues, please open an issue on GitLab.

Best Regards,

Chris