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.

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.

3. Install and run the Showcase

rails g svelte_on_rails:showcase

Additional: On Models, where you want to use the to_svelte helper, add exposes_to_svelte, for example:

class Book < ApplicationRecord
  exposes_to_svelte
end

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.login_count.label }: { user.login_count }</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.
    • Check uncached props.

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
  • 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