Turbo Native: How We Built a Mobile App Without React Native



This content originally appeared on DEV Community and was authored by Alex Aslam

“We launched our mobile app in 6 weeks—without writing a single line of Swift or Kotlin.”

When our CEO demanded a mobile app, our team groaned. None of us knew React Native, and the thought of maintaining two codebases (iOS + Android) made us shudder.

Then we discovered Turbo Native—the secret weapon that let us ship a fully native-feeling app using our existing Rails backend and zero custom API endpoints.

Here’s how it works, when to use it, and the brutal tradeoffs we learned the hard way.

1. What is Turbo Native?

The TL;DR

Turbo Native lets you:

  • Wrap your Rails app in a native shell (iOS/Android)
  • Reuse 100% of your HTML views
  • Add native navigation/gestures with minimal glue code

It’s not a cross-platform framework. Instead:

  • iOS: Uses WKWebView + native navigation (Swift/ObjC)
  • Android: Uses WebView + native nav (Kotlin/Java)

2. How We Built It in 6 Weeks

Step 1: The Native Shell

We started with the official Turbo iOS and Turbo Android templates:

// iOS (Swift)
let turboSession = WKWebViewConfiguration()
let turboNavController = TurboNavigationController()
turboNavController.route("/")  // 👈 Loads your Rails root_url
// Android (Kotlin)
val turboSession = TurboSession()
turboSession.visit("https://yourapp.com")

Key Insight: This is just a browser in native clothing—but with critical extras:

  • Native tab bars
  • Swipe-back gestures
  • Offline support

Step 2: Progressive Enhancement

We marked up our existing Rails views to trigger native behavior:

<!-- Show native back button -->
<meta name="turbo-native-navigation" content="back">

<!-- Use native tabs -->
<div data-turbo-native-tab="home">Home</div>
<div data-turbo-native-tab="profile">Profile</div>

<!-- Native pull-to-refresh -->
<turbo-frame id="feed" data-native-refresh="true">

Step 3: The Bridge

For device features (camera, GPS), we used Stimulus controllers + native callbacks:

// Rails: Stimulus controller
export default class extends Controller {
  takePhoto() {
    window.TurboNativeBridge.postMessage("requestCamera")
  }
}

// iOS: Handle the message
func webView(_ webView: WKWebView, didReceive message: WKScriptMessage) {
  if message.name == "requestCamera" {
    presentCamera()
  }
}

3. The Good, Bad, and Ugly

✅ Why We Loved It

  • Shipped 6x faster than React Native
  • Zero API changes (used existing HTML)
  • App Store approval in 24 hours (no JS engine = fewer red flags)

❌ Where It Hurt

  • No offline-first (without serious work)
  • Animations were clunky (compared to pure native)
  • Debugging = Safari Web Inspector (no React DevTools)

😱 The Biggest Surprise

Our App Store rating was higher than our competitor’s React Native app. Users couldn’t tell it was a web view because:

  • We used native navigation stacks
  • Added skeleton loading states
  • Avoided janky transitions

4. Turbo Native vs. Alternatives

Turbo Native React Native Flutter PWA
Code Reuse 90% 50% 100% 100%
Native Feel 85% 95% 90% 50%
Team Skills Required Rails + CSS JavaScript Dart Rails
Offline Support Limited Good Great Great

Best for:

  • Internal tools
  • CRUD-heavy apps
  • Teams with strong Rails skills

Avoid for:

  • Games
  • Video-heavy apps
  • Apps needing deep device integration

5. When to Go Hybrid

We mixed native screens for key flows:

// Swift: Show checkout natively
if path == "/checkout" {
  presentNativeCheckout()
} else {
  visit(path) // Default to Turbo
}

Hybrid wins:

  • Payment flows (better Apple Pay/Google Pay support)
  • Camera/upload screens
  • Complex animations

6. How to Get Started

1. Try the Demos

2. Audit Your Rails App

  • Fix responsive design issues
  • Add turbo-native meta tags
  • Test with Safari’s “Request Mobile Site”

3. Plan Your Native Extras

  • List required device APIs (camera, GPS)
  • Design native fallbacks for slow networks

“But What About Performance?”
Our benchmarks:

  • Cold start: 1.2s (vs. 0.8s native)
  • Navigation: 0.3s (vs. 0.1s native)
  • Memory usage: 30% higher than native

For 95% of apps, this doesn’t matter.

Tried Turbo Native? Share your wins/fails below!


This content originally appeared on DEV Community and was authored by Alex Aslam