RORK LABJP
MAX — Rork Max bills itself as the first web Swift app builder, publishing to the App Store in two clicks with no Xcode requiredAPPLE — It generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision ProEXPO — The standard tier builds native iOS and Android apps on React Native (Expo) from a plain-English descriptionFUNDING — Rork raised $2.8M from a16z, strengthening its position in AI no-code mobile developmentPRICE — Free to start, with paid plans from $25/month — an accessible entry point for solo developersWWDC — WWDC 2026 pushes Apple Intelligence forward, raising the value of native features and widening AI integration options for no-code appsMAX — Rork Max bills itself as the first web Swift app builder, publishing to the App Store in two clicks with no Xcode requiredAPPLE — It generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision ProEXPO — The standard tier builds native iOS and Android apps on React Native (Expo) from a plain-English descriptionFUNDING — Rork raised $2.8M from a16z, strengthening its position in AI no-code mobile developmentPRICE — Free to start, with paid plans from $25/month — an accessible entry point for solo developersWWDC — WWDC 2026 pushes Apple Intelligence forward, raising the value of native features and widening AI integration options for no-code apps
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.

Rork393Expo66Foundation Models2On-Device AINative ModuleReact Native157

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-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.
AI Models2026-04-22
Rork × LiveKit: Production Voice Agent Infrastructure for AI-Powered Apps
A complete guide to wiring LiveKit Agents into a Rork-generated React Native app and running low-latency AI voice agents in production.
📚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 →