◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Getting Started
◈ Getting Started/2026-10-17Intermediate

Before Moving to Expo SDK 58, List What Disappears in Your Own Code

A small audit script that scans your project for the APIs Expo SDK 58 removes, changes, or deprecates, with the output from a test project and the pitfalls I only noticed once I ran it.

Expo SDK 58UpgradeReact Native240Migration3Indie Development28Rork588

✦ Premium Article

My first reaction to the SDK 58 changelog was simply that it is long.

Removals, behavior changes, deprecations, each in its own section. By the time I reached the end, I could no longer say what the first section had contained. Understanding the notes is one task. Finding where they apply to your own project is another, and it is still waiting when you finish reading.

So this time I reversed the order. I pulled out only the items that can be searched for, turned them into a small script, and ran it against the project first. Judgment comes after the list exists.

Expo SDK 58 was released on October 15, 2026, according to the expo.dev changelog, and it moves React Native from 0.86 to 0.88. A project exported from Rork is an ordinary Expo project underneath, but as far as I could confirm, there is no announcement yet about when Rork itself will support SDK 58. Everything below is about upgrading an exported repository on your own.

Sort the items into three bins first

Listing the changelog as it stands does not make a checklist. I sorted by what you must do about each one.

  • REMOVED: the build or the type check stops if it remains. Highest priority
  • BEHAVIOR: it still runs, but the result differs. A human has to decide if that matches intent
  • DEPRECATED: it works today. Fix it next time, not on upgrade day

From the changelog, these are the items I made searchable.

BinTargetReplacement
REMOVEDInteractionManager, the root Touchable export, NativeMethods types, the Modal animated propPressable, instance types, animationType, and so on
REMOVEDDeep imports from react-native/Libraries/* (Strict TypeScript API is now the default)Imports from the public API
REMOVEDexpo-sqlite syncLibSQL and libSQLOptionslibSQL support itself is removed
BEHAVIORFile.write() becomes async (expo-file-system)await it, or use writeSync()
BEHAVIORexpo-notifications shows foreground notifications by defaultConfirm it is what you want
BEHAVIORNODE_ENV=test expo start now loads .env.developmentRethink where test env files live
DEPRECATEDFile.md5, ImageBackground, withLayoutContextFile.digest(), View plus Image, integrateWithRouter

The changelog also says some deprecated StatusBar props are removed, but I could not pin down which ones. The script includes networkActivityIndicatorVisible purely as an example, and you should check the official list to see whether it applies.

The full audit script

It runs on Node.js alone. SDK 58 expects Node 22.13 or later on the 22 line, 24.3 or later on the 24 line, or Node 26 and above; the odd-numbered 23 and 25 are not supported. There are no dependencies.

// audit-sdk58.mjs — SDK 58 へ上げる前に、プロジェクト内の「消える・変わる」API を一覧にする
// 使い方: node audit-sdk58.mjs [プロジェクトのパス]
import { readdirSync, readFileSync, existsSync, statSync } from 'node:fs';
import { join, relative, extname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
 
const SELF = fileURLToPath(import.meta.url); // 自分自身は検査対象から外す
 
const root = process.argv[2] ?? '.';
const SKIP = new Set(['node_modules', '.git', 'ios', 'android', '.expo', 'dist']);
const EXT = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs']);
 
// level: REMOVED=消える/BEHAVIOR=挙動が変わる/DEPRECATED=非推奨(今は動く)
const RULES = [
  { id: 'rn-interactionmanager', level: 'REMOVED', re: /\bInteractionManager\b/, why: 'RN から削除。requestAnimationFrame か、描画後に走らせたい処理を useEffect 側へ' },
  { id: 'rn-touchable-root', level: 'REMOVED', re: /import\s*\{[^}]*\bTouchable\b[^}]*\}\s*from\s*['"]react-native['"]/, why: 'Touchable のルート export が削除。Pressable へ' },
  { id: 'rn-nativemethods', level: 'REMOVED', re: /\bNativeMethods\b/, why: 'NativeMethods 型が削除。ViewInstance など instance 型へ' },
  { id: 'rn-modal-animated', level: 'REMOVED', re: /<Modal\b[^>]*\banimated\b/, why: 'Modal の animated prop が削除。animationType を使う' },
  { id: 'rn-deep-import', level: 'REMOVED', re: /from\s*['"]react-native\/Libraries\//, why: 'Strict TypeScript API が既定。Libraries/* の deep import は型エラー' },
  { id: 'rn-statusbar-ios-props', level: 'REMOVED', re: /<StatusBar\b[^>]*\bnetworkActivityIndicatorVisible\b/, why: 'StatusBar の非推奨 prop の一部が削除対象。この prop が該当するかは公式の変更履歴で確認(ここは例)' },
  { id: 'fs-file-write', level: 'BEHAVIOR', re: /\.write\(/, why: 'expo-file-system の File.write() は非同期に。同期のままなら writeSync()(File 以外の .write も拾うので目視)' },
  { id: 'fs-md5', level: 'DEPRECATED', re: /\.md5\b/, why: 'File.md5 は非推奨。File.digest() へ' },
  { id: 'sqlite-libsql', level: 'REMOVED', re: /\b(syncLibSQL|libSQLOptions|useLibSQL)\b/, why: 'expo-sqlite の libSQL 対応が削除' },
  { id: 'rn-imagebackground', level: 'DEPRECATED', re: /\bImageBackground\b/, why: '非推奨。View + 絶対配置の Image へ' },
  { id: 'router-withlayoutcontext', level: 'DEPRECATED', re: /\bwithLayoutContext\b/, why: '非推奨。integrateWithRouter へ' },
  { id: 'notif-foreground', level: 'BEHAVIOR', re: /from\s*['"]expo-notifications['"]/, why: 'フォアグラウンド通知が既定で表示される。意図した挙動か確認' },
  { id: 'nodeenv-test', level: 'BEHAVIOR', re: /NODE_ENV=test/, why: 'NODE_ENV=test で expo start すると .env.development を読む' },
];
 
function* walk(dir) {
  for (const name of readdirSync(dir)) {
    if (SKIP.has(name)) continue;
    const p = join(dir, name);
    const st = statSync(p);
    if (resolve(p) === SELF) continue;
    if (st.isDirectory()) yield* walk(p);
    else if (EXT.has(extname(name)) || name === 'package.json') yield p;
  }
}
 
const hits = [];
for (const file of walk(root)) {
  const lines = readFileSync(file, 'utf8').split('\n');
  lines.forEach((line, i) => {
    for (const r of RULES) if (r.re.test(line)) hits.push({ r, file: relative(root, file), line: i + 1, text: line.trim() });
  });
}
 
// ネイティブ側の確認(CNG でない場合に効く)
const notes = [];
if (existsSync(join(root, 'ios'))) notes.push('ios/ があります。CNG なら削除して再生成、手書き管理なら AppDelegate のシーン対応(SceneDelegate.swift)を確認');
if (existsSync(join(root, 'android'))) notes.push('android/ があります。R8 が release で既定オンになるため keep ルールを確認');
 
const order = { REMOVED: 0, BEHAVIOR: 1, DEPRECATED: 2 };
hits.sort((a, b) => order[a.r.level] - order[b.r.level] || a.file.localeCompare(b.file));
for (const h of hits) console.log(`[${h.r.level}] ${h.file}:${h.line}  ${h.r.id}\n    ${h.text}\n    → ${h.r.why}`);
const c = (l) => hits.filter((h) => h.r.level === l).length;
console.log(`\n集計: REMOVED ${c('REMOVED')} / BEHAVIOR ${c('BEHAVIOR')} / DEPRECATED ${c('DEPRECATED')}`);
notes.forEach((n) => console.log('NOTE: ' + n));
process.exit(c('REMOVED') > 0 ? 1 : 0);

A few notes on the design choices follow.

  1. The rules are an array, and each why names the replacement. The output tells you the next action as you read it, and adding a rule is one line
  2. The exit code depends on whether any REMOVED item exists. If you later put it in CI, "stop unless REMOVED is zero" works as is
  3. It ends with a note about ios/ and android/. Native code cannot be seen by a text search, so the script only says "this needs a separate check"
✦

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
✦You can list exactly which lines in your project are affected by SDK 58, with file and line numbers, before the build turns red
✦You can run a thirty-minute pre-upgrade check that sits between reading everything and upgrading first and fixing later
✦You can tell what a text search can and cannot catch, so you do not lean on the audit more than it deserves
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

◈ Getting Started2026-09-14
Rork No Longer Creates New Expo Projects: Keep Yours, or Rebuild It in SwiftUI?
You can no longer start an Expo project in Rork, but existing ones keep building and shipping. Here is how to decide whether to stay on Expo or rebuild in SwiftUI, and what quietly goes missing when you rebuild.
◈ Getting Started2026-09-08
Whether You Need Rork Max Is Answered by Your Permissions, Not the Price Page
When I cannot decide between standard Rork and Rork Max, I stop reading the price page. Instead I pull every OS capability my app actually asks for out of app.json and Info.plist, then sort them into what Expo covers, what a config plugin covers, and what truly needs native Swift.
◇ App Dev2026-08-16
My chart broke on day one, not at scale
A line chart that vanished for anyone with only a few days of data. The cause was a zero-height Y axis turning coordinates into NaN. Here is the measured behavior and the small normalization layer that fixed it.