---
title: 'Superglue 2.0 beta: React ❤️ Rails even more'
teaser: The Rails way of building Rails and React apps just got easier.
tags: ruby,web,ruby on rails,react,redux,javascript,hotwire,stimulus,turbo,superglue
author: Johny Ho
published_on: 2026-06-29
---

We're a few months shy from a 2.0 release of
[Superglue](https://thoughtbot.github.io/superglue/2.0.beta/). Its been exciting
designing what will be the BEST approach to developing Rails and React
applications.

For folks who are new, Superglue is a Rails first approach to building Rails and
React applications that we released [a year ago](https://thoughtbot.com/blog/superglue-1-0-react-rails-a-new-era-of-thoughtfulness).
There are no APIs. No client-side routing. And you can use the concepts you
already know: turbo streams, controllers, server-side routing, views, form
helpers, and more. You get rich, interactive React UIs driven by The Rails Way. Check
out our previous [alpha announcement](https://thoughtbot.com/blog/superglue-2-0-alpha-react-rails-turbo-streams)
or our [opensummit talk](https://www.youtube.com/watch?v=3_esl1bqY88)

Today we're announcing our 2.0 beta, and there's a lot to like:

## Easier to get started

We've now made it really easy to get started. Just use `createApp` to build a
Superglue app. Our rails generators `rails g superglue:install` will take care
of this for you.

```jsx
const { Provider, Outlet, ujs } = createApp({
  // The base url prefixed to all calls made by `visit` and `remote`.
  baseUrl: location.origin,
  // The global var SUPERGLUE_INITIAL_PAGE_STATE is set by your erb
  // template, e.g., index.html.erb
  initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
  // The initial path of the page, e.g., /foobar
  path: location.pathname + location.search + location.hash,
  // Callback used to setup visit and remote
  buildVisitAndRemote,
  // Mapping between the page identifier to page component
  mapping: pageIdentifierToPageComponent,
});

const root = createRoot(appEl);
root.render(
  <div onClick={ujs.onClick} onSubmit={ujs.onSubmit}>
    <Provider>
      <MyLayout>
        <Outlet />
      </MyLayout>
    </Provider>
  </div>,
);
```

## Support for esbuild, bun, webpack, and rollup

The install generator now supports all the major JavaScript bundlers that
`jsbundling-rails` supports. When you run `rails g superglue:install`, it will
detect your existing bundler configuration or prompt you to choose one. You can
also skip the prompt entirely with the `--bundler` flag:

```
rails g superglue:install --bundler=bun
```

Each bundler gets its own tailored configuration — including glob imports for
bun and rollup, so your `page_to_page_mapping` stays in sync with your views
automatically.

## Finalizing Super Turbo Streams

We've settled on the right amount of stream actions based on our experience
working on production applications: **append**, **prepend**, and **update**.
These three cover the vast majority of real-time UI patterns — adding items to
lists, updating existing records — without the complexity of a larger action
vocabulary.

The API mirrors what Rails developers already know from Turbo Streams:

```ruby
@message.broadcast_append_to "messages"
@message.broadcast_prepend_to "notifications"
@message.broadcast_update_to "messages"
```

And on the client side, subscribing is a one-liner with `useStreamSource`:

```jsx
const { connected } = useStreamSource(streamFromMessages)
```

You can also now use ActionCable or AnyCable. Just pass a cable consumer to
`createApp`:

```diff
+ import { createConsumer } from '@rails/actioncable'

  const { Provider, Outlet, ujs } = createApp({
    baseUrl: location.origin,
    initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
    path: location.pathname + location.search + location.hash,
    buildVisitAndRemote,
    mapping: pageIdentifierToPageComponent,
+   cable: createConsumer()
  });
```

Or if you're using AnyCable, just swap the import:

```diff
- import { createConsumer } from '@rails/actioncable'
+ import { createConsumer } from '@anycable/web'

  const { Provider, Outlet, ujs } = createApp({
    baseUrl: location.origin,
    initialPage: window.SUPERGLUE_INITIAL_PAGE_STATE,
    path: location.pathname + location.search + location.hash,
    buildVisitAndRemote,
    mapping: pageIdentifierToPageComponent,
    cable: createConsumer()
  });
```

## Give it a try!

```
gem install superglue --pre
```

## And much more

We're just getting started. Stay tuned for upcoming posts diving deeper into
fragments, types, stream responses and more.
