RORK LABJP
MAX — Rork Max builds native Swift apps instead of React Native, targeting the whole Apple ecosystemDEVICES — From one description it spans iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageNATIVE — It unlocks AR and LiDAR scanning, 3D games with Metal, Home Screen widgets, Dynamic Island, and on-device Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, joined by Peak XV and a16z SpeedrunPAPERLINE — Rork acquired the app builder Paperline and plans to stay acquisitive for engineering talentMARKET — With 743,000+ monthly visits, and Gartner expects 75% of new apps to be low-code or no-code by end of 2026MAX — Rork Max builds native Swift apps instead of React Native, targeting the whole Apple ecosystemDEVICES — From one description it spans iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageNATIVE — It unlocks AR and LiDAR scanning, 3D games with Metal, Home Screen widgets, Dynamic Island, and on-device Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, joined by Peak XV and a16z SpeedrunPAPERLINE — Rork acquired the app builder Paperline and plans to stay acquisitive for engineering talentMARKET — With 743,000+ monthly visits, and Gartner expects 75% of new apps to be low-code or no-code by end of 2026
Articles/AI Models
AI Models/2026-07-15Advanced

On-Device Image Classification: TFLite on React Native or Core ML on Rork Max — How I Chose After Building Both

Adding on-device image classification means choosing between TFLite on React Native and Core ML on Rork Max. I built the same feature both ways, measured the end-to-end breakdown, and worked out what the decision actually hinges on.

Rork Max224Core ML6TensorFlow LiteOn-Device AI6React Native209Expo143Image Recognition

Premium Article

Pick a photo, and the app decides on its own whether it is a night scene, a sky, or an abstract pattern — entirely on the device. When I went to add that small classifier to a wallpaper app, what stopped me was not the choice of model.

Do I bolt TensorFlow Lite onto the React Native (Expo) project that regular Rork produces? Or do I lean on the native Swift that Rork Max emits and go with Core ML?

The pricing gap matters too. Regular Rork starts free with paid plans at $25/month; Rork Max is $200/month. For a solo developer, that spread is not pocket change.

So I built the same feature both ways. What I learned is that the thing I had been trying to compare — inference engine speed — was the wrong variable entirely.

Three questions I settled before writing any code

Deciding these first matters. Skip them and you end up picking whichever one happened to work.

  1. Can the user wait for a result? Snapping one photo and classifying it is a different problem from tracking a live camera preview.
  2. Will I keep swapping the model? Shipping one off-the-shelf classifier is not the same as retraining on my own data and pushing updates.
  3. What else on the device will I want to reach for? Six months out, will widgets or the deeper parts of the photo library start looking tempting?

That third question turned out to be the one that decided it.

On React Native, "use TFLite" is not a single path

Start with the React Native (Expo) foundation that regular Rork generates. The first fork appears immediately.

You can go through the TensorFlow.js React Native bindings, or you can hit native TFLite directly over JSI. Both are "using TFLite," and they feel nothing alike in practice.

AspectVia tfjs-react-nativeDirect over JSI (react-native-fast-tflite and friends)
How the image travelsFile to Base64 string to Uint8Array to tensorArrayBuffer passed with close to zero copying
Where preprocessing livesIn JS — resize and normalize are tensor opsPushed to native or a frame processor
Ease of setupTestable in Expo GoRequires a development build
Where it bitesBase64 round trip, GC pressure, leaked tensorsMismatched model input specs and dtypes

Convenience won at first, so I built the tfjs route. It works. It genuinely works. But there was a beat of hesitation between pressing the shutter and seeing a result, and it never went away.

The easy path, and the thing that kept nagging

// utils/classifyViaTfjs.ts
import * as tf from '@tensorflow/tfjs';
import { decodeJpeg } from '@tensorflow/tfjs-react-native';
import * as FileSystem from 'expo-file-system';
 
// The image becomes a *string* and then gets read back. Remember this line.
export async function classifyViaTfjs(model: tf.GraphModel, uri: string) {
  const b64 = await FileSystem.readAsStringAsync(uri, {
    encoding: FileSystem.EncodingType.Base64,
  });
 
  const bytes = tf.util.encodeString(b64, 'base64');
  const image = decodeJpeg(new Uint8Array(bytes.buffer));
 
  // Down to 224x224, normalize to -1..1, add the batch dimension
  const input = tf.tidy(() =>
    tf.image.resizeBilinear(image, [224, 224]).div(127.5).sub(1).expandDims(0)
  );
 
  const logits = model.predict(input) as tf.Tensor;
  const probs = await logits.data();
 
  // tidy cannot span an await, so anything created outside it is yours to free
  tf.dispose([image, input, logits]);
 
  return probs;
}

The tf.tidy wrapper reclaims intermediate tensors in one sweep. It cannot cross an await, though, so decodeJpeg output and predict output still need an explicit dispose. Miss that and memory starts visibly climbing somewhere around the fortieth image.

The reason this deserves care: a leak like this is invisible during the ten images you test with. It shows up when a user scrolls an album for a while.

But the real problem was not the leak — it was how the image traveled. File to Base64 string, across the JS bridge, back to a Uint8Array. A 2MB photo becomes roughly a 2.7MB string the moment you Base64 it.

Inference was fast, and I was still waiting. That told me what to measure.

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
Why preprocessing and data handoff dominate the timeline instead of inference, plus a probe you can drop in to get the breakdown on your own device
The two routes for shipping TFLite (via tfjs versus via JSI) and the exact place where one of them stalls
A decision table for when the jump from $25/month to $200/month is actually justified, derived from feature requirements rather than benchmarks
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-14
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.
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 →