●MAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessage●PUBLISH — Rork Max ships 2-click App Store publishing and runs $200/month●RN — The standard Rork builds native iOS/Android apps with React Native (Expo) — the quicker path to a working app●PRICE — Rork is free to start, with paid plans from $25/month●FUND — Rork raised $2.8M from a16z; the platform now sees 743k+ monthly visits with 85% growth●FLOW — Describe your app in plain English and Rork generates deployable code that can use the camera, notifications, and more●MAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessage●PUBLISH — Rork Max ships 2-click App Store publishing and runs $200/month●RN — The standard Rork builds native iOS/Android apps with React Native (Expo) — the quicker path to a working app●PRICE — Rork is free to start, with paid plans from $25/month●FUND — Rork raised $2.8M from a16z; the platform now sees 743k+ monthly visits with 85% growth●FLOW — Describe your app in plain English and Rork generates deployable code that can use the camera, notifications, and more
Trimming App Size for Rork Max Apps: App Thinning and On-Demand Resources
Rork Max ships images and fonts straight into the bundle, so a generated SwiftUI app quietly grows heavy. Here is how I use App Thinning and On-Demand Resources to shrink the first download, with the device numbers I measured and a size budget you can run.
One morning I opened App Store Connect for my own wallpaper app and the download size had crossed 180MB. I thought I had only added a few new screens with Rork Max, yet the first download had crept up toward the cellular warning line.
When I traced it, the generated code was placing high-resolution images and several custom fonts straight at the root of the bundle. Rork Max is excellent at producing a screen that looks finished as fast as possible, but it does not manage your delivery size for you. That was the lesson of the morning.
As an indie developer who has run apps for years, I have learned that size is a metric that bites you quietly. What follows is the full path of taking the Swift native code Rork Max emits and shrinking the first download with App Thinning and On-Demand Resources, with the numbers I actually measured.
Where app size actually hurts
The reason to care about size is not aesthetics. It is the drop-off right before install.
The App Store caps downloads over cellular, and above that cap the user sees a "connect to Wi-Fi" warning. Someone who reached your store page through an ad or a referral often leaves at that single screen. I have an app where pushing the size down into the low 90s of megabytes noticeably improved the first-install completion rate in my own tracking.
The second cost is the traffic of every update. If you ship weekly, your users download again and again. A few dozen megabytes per download adds up.
What App Thinning does for you automatically
App Thinning is Apple's mechanism, and it has three parts. Slicing extracts only the resolution each device needs. On-Demand Resources let you fetch resources later instead of bundling them up front. Bitcode, which used to be the third part, has been retired.
The easy misunderstanding is that Slicing only works when assets live in the asset catalog. Put an image at the bundle root — exactly what generated code tends to do — and Slicing skips it, so every resolution ships to every device. That is the most common reason a Rork Max build balloons.
✦
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
✦How to structure your asset catalog so Slicing actually kicks in, and how to fix the bundling mistakes generated code tends to make
✦An NSBundleResourceRequest implementation that moves a 40MB pack out of the first download via On-Demand Resources
✦A size budget in megabytes, plus the check routine and decision rules that keep it from creeping back up
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.
The first move is to pull the loose images out of the bundle root and into the asset catalog. Assign each image to its 1x / 2x / 3x slot inside Assets.xcassets, and Slicing will deliver just the one variant a device needs.
// ❌ Common right after generation (bundle root, not sliced)Image(uiImage: UIImage(named: "hero_background.png")!)// ✅ Through the asset catalog (no extension, Slicing applies)Image("hero_background")
When you find an image loaded by a filename with an extension, that is the signal it points at the bundle root. Re-register it in the asset catalog and reference it by name without the extension. That alone stops the huge 3x image from shipping uselessly to 1x and 2x devices.
Apply the same scrutiny to fonts. It is common to double-bundle the same family as separate files for body and heading, or to leave a weight you stopped using. Trim down to the weights actually rendered on screen and several megabytes simply vanish.
Moving the first download off your back with ODR
Large resources that Slicing cannot cut go to On-Demand Resources (ODR): a tutorial video, extra theme packs, the high-resolution wallpaper sets you do not need on first launch.
With ODR you tag assets and fetch them when needed. After setting the tag on the resource in Xcode's asset catalog, you request it from code like this.
import Foundationfinal class ThemePackLoader { private var request: NSBundleResourceRequest? func loadThemePack(tag: String) async throws { let req = NSBundleResourceRequest(tags: [tag]) // Observe req.progress if you want to show a UI indicator self.request = req let available = await req.conditionallyBeginAccessingResources() if available { return // Already present on the device } try await req.beginAccessingResources() } func release() { request?.endAccessingResources() request = nil }}
There are three points worth stressing. First, conditionallyBeginAccessingResources checks whether the pack is already fetched, so you avoid a pointless re-download. Second, you must call endAccessingResources when finished or the benefit of ODR fades. Third, the fetch can fail on a weak network, so always provide a path that falls back to a low-resolution copy bundled in the app. In production, a review from someone whose fetch failed on the subway will reflect exactly whether you designed that fallback.
In my case I recommend bundling only the default theme and moving the extra wallpaper packs — about 40MB in total — to ODR. The first download gets lighter, and the extra packs are fetched only by people who want them, so average traffic drops as well.
Setting a size budget and running it
Trim once and forget, and the app grows again. So I run a per-app size budget. The table below is the target I use for my own indie wallpaper apps.
Category
Target
Why
First download (after Slicing)
under 100MB
Stay below the cellular warning and protect first-install completion
Total bundled assets
under 30MB
UI, icons, and a minimal set of fonts only
Delivered via ODR
under 50MB per tag
So the fetch completes even underground or on a weak signal
Installed size
light enough not to burden free space
Give no reason to uninstall
With this budget in place, every time you add a screen you can decide on the spot whether an image is bundled or ODR. The judgment stops depending on memory, and you avoid the slow creep.
Trimming while you measure
Cutting by feel is dangerous, so always read the numbers. Xcode's Organizer has an App Size Report showing per-device delivery size and what occupies it.
# Export the post-thinning size from an archivexcodebuild -exportArchive \ -archivePath MyApp.xcarchive \ -exportPath ./thinned \ -exportOptionsPlist thinning.plist# In thinning.plist set <key>thinning</key><string><all-variants></string>
Open the resulting App Thinning Size Report.txt and you get per-device compressed and uncompressed sizes. I record these numbers on every release and track the delta from last time. If it grew, the first suspect is the assets from a screen I added recently.
Measuring also surfaces surprises. In one app, 12MB of unused localization images was still sitting in the asset catalog, referenced from nowhere in code. Without the report, I would probably never have noticed.
Knowing where to stop
A final word on where to spend effort. Size reduction has no natural floor. But the line users actually feel is fairly fixed: whether the first download crosses the cellular warning, and whether they can start using the app right after launch. Hold those two and further effort yields less and less.
I keep three things at the top: make Slicing reliably apply, move only the obviously large resources to ODR, and keep recording the size budget. The rest is polish for when there is spare time.
Start by searching your own Rork Max project for any image still loaded with a file extension. That is the first step toward reclaiming size. Thank you for reading.
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.