Runtime performance
Token cost measures what it costs to build; this page measures what you get. Every implementation was rebuilt in Release configuration from its preserved source tree and profiled on one fixed simulator (iPhone 17 Pro) — no new agent trials were needed, because performance belongs to the artifact, not the agent’s path to it. Raw per-app JSON is in the repository ↗.
App size was measured on simulator builds, which are not app sizes
As first published, size came from the Release-iphonesimulator .app directory. That bundle carries an x86_64 slice that never ships and full symbol tables: NativeScript’s 93.3 MB was 67.2 MB of NativeScript.framework, whose binary was a 59 MB fat Mach-O (30 MB x86_64 + 29 MB arm64) holding 49,215 symbols. Both arms were inflated, but not by the same proportion — NativeScript shed 45% on re-measurement and Expo 50% — so the published ratio was wrong as well as the absolute figures. Every app was re-measured as an unsigned arm64 device archive, which runs the strip and postprocessing an App Store build gets. The direction of the finding is unchanged and the gap is slightly wider. Memory, launch, and CPU were unaffected: they were always simulator measurements and remain so.
| Figure | As published | Corrected |
|---|---|---|
| NativeScript bundle | 93.3 MB | 51.1 MB |
| Expo bundle | 57.1 MB | 28.7 MB |
| NativeScript executable | 23.4 MB | 11.8 MB |
| Expo executable | 5.3 MB | 1.3 MB |
| Headline gap | −39% | −44% |
28.7 vs 51.1 MB; main executable 1.3 vs 11.8 MB.
301 vs 302 ms to foreground-active.
RSS 228 vs 216 MB; footprint 34 vs 40 MB.
Every implementation rebuilt in Release untouched, both arms.
Debug builds carry development-only weight — unoptimized code and development-only attach paths — so they are never measured. Each trial’s final source tree (preserved as a git branch) was rebuilt with -configuration Release and archived. Measuring all implementations rather than one per side turns implementation variance into data: across 8 independently agent-built apps per arm, every nativescript archive came out at exactly 51.1 mb and expo spanned only 27.4–28.7 mb, while idle rss varied 214–216 mb. size and runtime characteristics are properties of the framework, not of how the agent wrote the app — which is why one app per side would have been enough here, and why the spread that does exist is worth showing.
Every app, no exclusions: All 16 free-choice implementations rebuilt in Release without modification — no build failures on either arm. React Native Debug builds do not embed the JS bundle (they fetch it from Metro at runtime), so every measurement and functional check here runs on Release builds, which embed on both arms.
Almost none of either bundle is the app the agent wrote. NativeScript ships an 11.8 MB executable with the V8-based runtime metadata compiled in, plus a 37.1 MB NativeScript.framework — 96% of its total. Expo ships a 1.3 MB executable over React (11.5 MB), Hermes (4.8 MB) and the Expo module frameworks (7.6 MB). Both are dominated by their runtime, and Expo’s is the smaller one.
Size is an unsigned arm64 device archive per app (xcodebuild archive, generic/platform=iOS), which runs the same strip and postprocessing an App Store build gets. Uncompressed and before App Store thinning, so these are upper bounds on download size. Memory, launch, and CPU below come from simulator builds instead, and are not comparable to these figures.
| Release, simulator (median) | NativeScript (n=8) | Expo (n=8) | Δ |
|---|---|---|---|
| Idle RSS | 216 MB | 228 MB | +6% |
| Idle physical footprint | 40 MB | 34 MB | −15% |
| Cold launch → foreground-active | 302 ms | 301 ms | ~equal |
| Launch-burst settle (CPU quiesce) | 1.45 s | 1.55 s | +7% |
| Idle CPU | 0.0% | 0.0% | equal |
5 cold launches per app, terminated between runs; launch timing from just before invocation to the OS foreground-active marker in the system log, CPU-quiesce fallback recorded alongside. Idle sampled 10×1 s after a 12 s settle. Both frameworks idle clean at 0.0% CPU on a static screen.
| Feature path (median ms, range) | NativeScript | Expo | Verdict |
|---|---|---|---|
| Nav → Health screen rendered | 2,220 (1,799–2,268) | 1,998 (1,359–2,254) | Expo ~10% faster |
| 7-day HealthKit query → rows rendered | 1,069 (1,044–1,097) | 1,075 (1,029–1,097) | tie — the OS API dominates |
| Log 500 steps → list refreshed | 513 (369–643) | 386 (355–403) | Expo ~25% faster |
| Nav → Transcribe screen rendered | 2,168 (1,736–2,192) | 2,205 (1,747–2,219) | tie |
Measured by a generic external UI-test driver tapping every app through its real flows by the spec-pinned labels, 3 iterations per app, fresh launch per iteration, permission sheets auto-granted. The heavy read path is a dead tie — 1,069 ms against 1,075 ms, a 0.6% gap — confirming that the OS API, not the framework, dominates it. Expo takes the write→refresh round trip, though NativeScript’s wide range (369–643 ms) traces to differing agent refresh strategies, so that is partly implementation choice.
Transcription is simulator-blocked identically on both frameworks: SFSpeechRecognizer’s server path rides Siri infrastructure the Simulator lacks. All 26 apps surfaced the error in their status line per spec rather than crashing. It is a physical-device metric.
Not measured for this pairing. The suite requires a hand-written bench app plus an equivalent native fixture per framework; NativeScript has one, Expo does not. Building it would test whether Expo’s synchronous JSI modules land near NativeScript’s ~1 µs direct binding or an order of magnitude above it. Worth doing; not done here, and not claimed.
- iOS Simulator on one Mac: absolute numbers are not device numbers — only the comparative readings transfer, and they share host, runtime, and interleaved scheduling.
- No scroll/FPS metric: the spec’d app has no scroll-stressing surface, so neither framework’s rendering under list or animation load is tested here.
- JS↔native bridge micro-latency is not separately instrumented (that would require modifying the agent-built apps); it shows up indirectly in the tap-to-result timings, where it proved immaterial.