RORK LABJP
MAX — Rork Max is built on Claude Code and Claude Opus 4.6, generating native Swift apps directly instead of React NativeAPPLE — Rork Max targets the whole Apple ecosystem: iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageWORKFLOW — In practice, users settle into letting the AI scaffold while they rewrite the state management and data layer themselvesSEED — Rork raised a $15M seed led by Left Lane Capital in April, with Peak XV, True Ventures, and a16z Speedrun joiningPAPERLINE — Rork acquired app builder Paperline and says it will stay acquisitive to bring in engineering talentREVIEW — Three-month revisit reviews are growing, clarifying where the tool shines and where it doesn'tMAX — Rork Max is built on Claude Code and Claude Opus 4.6, generating native Swift apps directly instead of React NativeAPPLE — Rork Max targets the whole Apple ecosystem: iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageWORKFLOW — In practice, users settle into letting the AI scaffold while they rewrite the state management and data layer themselvesSEED — Rork raised a $15M seed led by Left Lane Capital in April, with Peak XV, True Ventures, and a16z Speedrun joiningPAPERLINE — Rork acquired app builder Paperline and says it will stay acquisitive to bring in engineering talentREVIEW — Three-month revisit reviews are growing, clarifying where the tool shines and where it doesn't
Articles/AI Models
AI Models/2026-06-14Advanced

Calling Apple Foundation Models from a Rork (Expo) App: Bridging On-Device AI Through a Native Module

Rork generates Expo (React Native) apps, but Apple Foundation Models ships as a Swift framework you can't touch from JavaScript. Here's how to write an Expo Modules API bridge, gate it by availability, and fall back to the cloud on unsupported devices.

Rork502Expo139Foundation Models4On-Device AI5Native Module2React Native202

Premium Article

Generate an app from a prompt in Rork and what you get is an Expo (React Native) project. Apple's on-device AI, Foundation Models, ships as a Swift framework. So the moment you decide you want an on-device LLM inside a Rork-built app, you hit a wall: JavaScript can't reach it directly.

I've run wallpaper and wellness apps as an indie developer for years, and one thing has been hammered into me repeatedly: "shipping a new OS feature to every user" and "running it on the latest devices only" are two completely different things. Foundation Models is an iOS 26+ on-device capability, so calling it naively quietly abandons readers on older hardware. In this article we build a production-grade setup that bridges Swift's Foundation Models through the Expo Modules API and silently routes to the cloud when the environment can't support it.

The design philosophy of using on-device inference as the primary path and escaping heavy work to the cloud is covered in the on-device-first inference router, and the prerequisite of using Foundation Models from native Swift is covered in the Apple FoundationModels implementation guide. This piece narrows in on the wiring that sits between those two: how you actually call that framework from an Expo app.

Why JavaScript Can't Call It Directly

Foundation Models is a Swift-only API you reach via import FoundationModels. The React Native bridge only passes JSON-equivalent values between JavaScript and Objective-C/Swift, so a Swift type like LanguageModelSession can't cross over to JS as-is.

This is where many people go hunting for an off-the-shelf package like expo-apple-intelligence. But Foundation Models is recent, and thin wrappers aimed purely at Expo apps aren't yet stable. I tend to decide that rather than being dragged around by someone else's black-box wrapper and its version churn, I'd rather write and own a hundred-line module myself — and I'll take that approach here too. There are only three things to do: receive a prompt as a string, call Foundation Models on the Swift side, and return the result string through a Promise. For that scope, a hand-written module reads more clearly and you can fix it yourself when it breaks.

The Swift Side: Wrapping Foundation Models in an Expo Module

In the Expo Modules API, you just define AsyncFunctions on a class that extends Module, and you get functions JS can await. To build a local module, start from npx create-expo-module --local on-device-ai, then rewrite the generated ios/OnDeviceAIModule.swift like this.

import ExpoModulesCore
import FoundationModels
 
public class OnDeviceAIModule: Module {
  public func definition() -> ModuleDefinition {
    Name("OnDeviceAI")
 
    // Tell JS whether this device can run the on-device LLM.
    // Anything other than "available" means JS should switch to the cloud.
    AsyncFunction("availability") { () -> String in
      if #available(iOS 26.0, *) {
        switch SystemLanguageModel.default.availability {
        case .available:
          return "available"
        case .unavailable(.deviceNotEligible):
          return "device_not_eligible"
        case .unavailable(.appleIntelligenceNotEnabled):
          return "not_enabled"
        case .unavailable(.modelNotReady):
          return "model_not_ready"
        case .unavailable:
          return "unavailable"
        }
      } else {
        return "os_too_old"   // below iOS 26
      }
    }
 
    // Take a prompt, return generated text.
    // Using a promise bridges Swift's async/throws straight into a JS exception.
    AsyncFunction("generate") { (prompt: String, promise: Promise) in
      guard #available(iOS 26.0, *) else {
        promise.reject("UNSUPPORTED", "On-device generation is unavailable below iOS 26")
        return
      }
      Task {
        do {
          let session = LanguageModelSession()
          let response = try await session.respond(to: prompt)
          promise.resolve(response.content)
        } catch {
          promise.reject("GENERATION_FAILED", error.localizedDescription)
        }
      }
    }
  }
}

The single most important thing here is the if #available(iOS 26.0, *) guard. Even in code that imports FoundationModels, as long as you keep Foundation Models-specific types out of anything outside the guard, the framework is weak-linked and the app still launches on pre-iOS-26 devices. I keep availability as its own function and guard again at the top of generate because that lets the JS side survive both "branch on availability before calling" and "accidentally call generate on an old device." In production the latter always happens eventually, so I defend twice.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
If you were stuck wanting on-device AI in your Expo app but couldn't reach the Swift framework from JS, you'll now have a working bridge you wrote and control yourself
You can turn a naive call that crashes on pre-iOS-26 or ineligible devices into something you can ship to every user, guarded by an availability check and a cloud fallback
You'll be able to weak-link the system framework through EAS Build and decide, with a real sense of device distribution, how to pass review and staged rollout
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

AI Models2026-06-19
Before You Pay $200/mo for Rork Max, Map How Far Expo Reaches in Three Tiers
Wanting widgets or Live Activities makes Rork Max tempting, but most of those features are reachable from the Expo setup that standard Rork generates. Here is how I sort each Apple-native feature into three tiers—reachable in Expo, reachable with a custom module, or where Max is the pragmatic answer—and verify which tier my app is in before paying.
AI Models2026-06-13
Routing inference on-device first and escaping to the cloud only when it's worth it, in a Rork app
Build a tiered, fallback-based inference router in a Rork (Expo) app: cache to on-device to Private Cloud Compute to a remote API (Claude/Gemini). Working TypeScript covering budgets, timeouts, caching, and image routing.
AI Models2026-05-08
How I Stop Rork's AI From Generating Outdated Library Code — My Version-Pinned Prompt Template
A practical look at why Rork Max sometimes generates outdated API code, the version-pinned prompt template I rely on every day, and the device-level checks I use to catch the cases where mismatches still slip through.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →