RORK LABJP
SDK57 — Expo SDK 57 landed, moving React Native from 0.85 to 0.86 while React stays at 19.2, and it is meant to ship no breaking changesCADENCE — The release hints at a new cadence: small, non-breaking upgrades slotted between the larger SDK releases, which makes keeping up easier to planRN086 — React Native 0.86 highlights include edge-to-edge fixes on Android, light and dark mode emulation in React Native DevTools, and rendering, layout, and animation fixesPREBUILD — expo prebuild improved how it clears and regenerates native directories, and expo-dev-client picked up iOS enhancementsIOS27 — iOS 27 reached beta 4 on July 20 and opened to public beta testers on July 22, so it is time to check generated apps ahead of the autumn releaseAND17 — Starting with Android 17, traditional Developer Previews are gone, replaced by continuously updated Canary buildsSDK57 — Expo SDK 57 landed, moving React Native from 0.85 to 0.86 while React stays at 19.2, and it is meant to ship no breaking changesCADENCE — The release hints at a new cadence: small, non-breaking upgrades slotted between the larger SDK releases, which makes keeping up easier to planRN086 — React Native 0.86 highlights include edge-to-edge fixes on Android, light and dark mode emulation in React Native DevTools, and rendering, layout, and animation fixesPREBUILD — expo prebuild improved how it clears and regenerates native directories, and expo-dev-client picked up iOS enhancementsIOS27 — iOS 27 reached beta 4 on July 20 and opened to public beta testers on July 22, so it is time to check generated apps ahead of the autumn releaseAND17 — Starting with Android 17, traditional Developer Previews are gone, replaced by continuously updated Canary builds
Articles/Dev Tools
Dev Tools/2026-07-28Advanced

Counting what prebuild --clean will erase before you upgrade to Expo SDK 57

A raw diff between two generated ios/ trees showed 649 changed lines; only 3 were real edits. How to count what prebuild --clean erases, and move it into a config plugin.

Rork522Expo152prebuild2config plugin2Expo SDK 57upgradesnative codeReact Native214

Premium Article

Expo SDK 57 shipped with React Native 0.86, and the release notes describe it as a non-breaking step up from 0.85. Following along should be cheap.

Still, before running expo prebuild --clean on one of the Rork-generated apps I maintain as an indie developer, I wanted an answer to a smaller question.

How many hand edits are actually sitting in ios/?

Rork gives you a project you own. You open the generated ios/ in Xcode, add a linker flag, drop one SDK initialization line into AppDelegate. Those edits feel trivial at the time. Three months later you have forgotten every one of them, and --clean removes them without comment.

So I built something that counts only the edits that would disappear. The numbers it produced were not what I expected.

A big diff tells you nothing about risk

I built a fixture that imitates two consecutive prebuild outputs for the same ios/ tree: 320 source entries, a 331-line project.pbxproj. The baseline is untouched generator output. The current copy carries three edits of the kind you actually make.

LocationEdit
MyApp/AppDelegate.mmOne inserted line: [FIRApp configure];
MyApp/Info.plistAdded NSCameraUsageDescription
MyApp.xcodeproj/project.pbxprojAdded OTHER_LDFLAGS = "-ObjC"

Three meaningful lines. Here is what a plain diff reports:

$ diff -rq ./baseline ./current | wc -l
6

$ diff -r ./baseline ./current | grep -c '^[<>]'
653

$ wc -l < ./baseline/MyApp.xcodeproj/project.pbxproj
331

$ diff ./baseline/.../project.pbxproj ./current/.../project.pbxproj | grep -c '^[<>]'
641

A 331-line file producing 641 changed lines. Practically every line on both sides is reported as different.

The cause is the pbxproj object ID. Xcode identifies every object in a project file with a 24-digit hex token, and those tokens are regenerated wholesale on every prebuild. Nothing about the content changed; every line still reads as new.

Which means diff volume carries no signal at all about risk. Three lines worth protecting are sitting somewhere inside 653 lines of churn — restricted to the files actually worth scanning, 3 meaningful lines out of 649, or 0.46%. If you do not know that ratio before running --clean, you will not notice when those three lines are gone.

What to skip, and what to normalize

Narrowing the scope happens in two stages.

Never look at these — directories where a diff has nothing to say:

  • Pods/ — output of pod install. The information worth keeping lives in Podfile
  • build/, DerivedData/, .gradle/, app/build/ — build intermediates
  • xcuserdata/ — Xcode UI state, different for every person who opens the project

Look, but flatten the churn — expressions that change without meaning anything:

RuleMatchesReplaced with
pbxproj object ID24-digit hex tokens<OBJID>
CocoaPods checksum40-digit hex tokens<SHA1>
Generation timestampISO 8601 datetimes<TIME>
Absolute paths/Users/…, /home/…<PATH>

The absolute path rule earns its place the moment you move machines or share the work. A CI container and a local Mac have different home directories, and that alone marks every generated xcconfig as changed.

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
Of 649 changed lines between two generated ios/ trees, exactly 3 were real hand edits. An ablation run shows which single normalization rule removes 643 of the false positives
A complete script that counts only the edits a regeneration would destroy and exits 1 when any exist. It runs in 0.04s on a 320-source tree, so it drops straight into CI as an upgrade gate
The full config plugin that takes those counted edits and makes them survive prebuild --clean, including verified idempotency and why a missing anchor should abort rather than warn
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

Dev Tools2026-05-30
Managing Native Settings Across Rork-Exported Apps with a Custom Expo Config Plugin
Tired of re-typing your AdMob ID and ATT string every time prebuild wipes your Info.plist? Here is how I made native settings reproducible with a custom Expo config plugin and shared it across six wallpaper apps.
Dev Tools2026-07-27
When to Raise Your Minimum iOS Version — Count Leftover Branches, Not User Percentages
Judging a minimum OS bump by usage share produces the same answer every year, so the decision never happens. Here is the annotation convention, the sweep script that counts how many branches each candidate floor would retire, and what to watch for 30 days after.
Dev Tools2026-07-26
What Filtering Out Prerelease OS Devices Cost Me — Separating Telemetry Tracks Instead of Dropping Them
Filtering prerelease OS devices out of telemetry left me with no warning signs on GA day. Here is the rebuild: an os_track dimension, a remote GA baseline, split alert thresholds, and a release gate that separates blockers from fixes.
📚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 →