Debugging Hotwire Native - Understanding Hotwire Native
When I recently attended RailsWorld, I had the chance to do a lightning talk titled “Debugging Hotwire Native”, which was 10 minutes in length. It was a ton of fun, but I think it would be more useful to share what I learned about debugging Hotwire Native Applications here in more detail so people can revisit it from time to time.
In this article, we will not cover specific techniques but provide a quick overview of how Hotwire Native works. Despite the technology becoming increasingly established, I often encounter seasoned developers who have gaps in their knowledge. This is understandable because to understand Hotwire Native, you must understand the Hotwire philosophy.
HTML Over the Wire AKA Hotwire
When developing native apps, you can choose to build your UI using a wide range of technologies. The choice is extensive. You can go full native with the modern frameworks of SwiftUI and Jetpack Compose. You can use older native frameworks, such as Android Views or UIKit, and you can even mix and match them.
It doesn’t stop there, as there are also React Native, Ionic, Xamarin, and Flutter.
All these options have their own way of building the UI for your application.
Hotwire Native puts all that aside and instead uses the web browser inside your app to render views built by HTML while utilizing native navigation.
There are three main components to understand. TurboJS, Native Adapters and Bridge Components.
Let’s look at each one.
Understanding TurboJS
Hotwire Native does not work without Turbojs. This is obvious to people who are embedded in the Rails ecosystem but less obvious to those outside and I totally understand the confusion.
So what is TurboJS exactly? Simply put, it intercepts all clicks on the same domain, prevents the default browser action, changes the URL using the History API and changes the page contents using the fetch api.
It does this for form submissions and handles the merging of the head and body tags. It is a very easy way to achieve an SPA-like app but without the headache.
Since it’s the head tag that tells the browser to fetch assets such as stylesheets, this is quite a clever trick on the part of the TurboJS creators, albeit it’s not without its price.
Developers who use TurboJS need to understand its cases, but thankfully, the documentation does a great job.
The key thing to understand from a Hotwire Native perspective is the concept of Application Visits. This then leaves you to learning about the iOS and Android Adapters.
Native Adapters
Once you understand Turbo, debugging and building Hotwire Native applications is much easier.
TurboJS utilises the adapter pattern to implement low-level functionality that responds to browser events. You can read the code of the default browser adapter here
The Hotwire Native iOS and Android implement their own native adapters that are initialised with the web view as soon as the app is launched using the immediately invoked function technique that JS provides.
These adapters are the bridge between your Rails app and the native adapters. And speaking of bridges.
Bridge Components
The final piece of the puzzle when it comes to debugging Hotwire Native apps is understanding how Bridge Components work.
Instead of just sending you to the source code or the documentation, I want to show you this image.

For me, understanding that it’s a simple system that sends messages back and forth helped me solidify where to start when things go wrong.
In the following article, we will explore some questions to ask yourself when debugging and how to answer them.