Publishing a React Native app to the App Store, solo
Foodproof has been live on the App Store for a few weeks now. Here’s the actual checklist we run for every release, including the pitfalls that cost us time along the way. Nothing made up here, this is literally our process.
Before you archive
Three things to check before touching Xcode:
- the version in
package.jsonis up to date MARKETING_VERSIONandCURRENT_PROJECT_VERSIONare bumped in the Xcode project (they show up in several places in the.pbxproj, agrephelps catch every occurrence)- the screenshot mode flag is off
grep -n "MARKETING_VERSION\|CURRENT_PROJECT_VERSION" ios/foodproof.xcodeproj/project.pbxproj
We also run the test suite and the linter first. Not because it’s glamorous, but because an archive that half-fails on a broken test is much more expensive to debug inside Xcode than in the terminal.
Archiving
Two details that look small and cost you a good half hour if you skip them:
xcpretty (the tool that formats build logs nicely) crashes without an explicit UTF-8 encoding in the terminal. So, before anything else:
export LANG=en_US.UTF-8
And Metro needs to be running before you open Xcode, otherwise the build waits about fifteen seconds and falls back to a stale JS bundle.
npx react-native start
Then open the workspace, not the .xcodeproj (CocoaPods relies on it to inject the pods):
open ios/foodproof.xcworkspace
Scheme foodproof, destination “Any iOS Device (arm64)”, then Product → Archive. The command-line equivalent, if you want to script it into a CI pipeline:
xcodebuild -workspace ios/foodproof.xcworkspace \
-scheme foodproof \
-configuration Release \
-archivePath build/foodproof.xcarchive \
archive | xcpretty
Uploading and TestFlight
From the Organizer, Distribute App → App Store Connect → Upload, keeping “Upload your app’s symbols” checked (useful the day you need to read a crash report).
Internal testers see the build immediately, no review needed. External testers trigger a Beta App Review, which usually takes a day or two the first time. Once a build has been through TestFlight, you don’t need to re-archive it to submit for production, it’s the same binary.
Going to production
Once the build is attached in App Store Connect, there’s the “What’s New” field to fill in. It’s required even for a 1.0 release, as soon as a French localization is active. Apple blocks submission if you leave it blank.
The rest is routine: check the metadata, the screenshots, the privacy label, then Submit for Review. On review time, keep your expectations loose: somewhere between 24 hours and a few days, it varies.
The pitfalls that cost the most time
Screenshot dimensions. Uploading a 1320×2868 screenshot into the 6.5-inch slot (which expects 1284×2778) gets the whole binary rejected, not just the image.
Seller name. You cannot change it from the App Store Connect UI, it comes from the legal entity registered with Apple Developer. We had to go through Apple Developer Support for this, budget a few days of email back-and-forth.
Keywords. Don’t repeat words already in your app name or subtitle in the keywords field: it’s a shared 100-character budget, every repeated word is a wasted word.
Xcode 26. This one is still unresolved as I’m writing this: Xcode 26 introduced a module verification step that isn’t compatible with how React Native 0.73 generates its module maps. The build fails at the “Compile Swift / Verify module” step. The only reliable workaround for now is staying on Xcode 15.x for release builds (and don’t try disabling the verifier, it breaks other things).
The reviewer account. If your app requires a login, provide a dedicated test account in the review notes, otherwise expect a rejection for “unable to test the core functionality.”
None of this is rocket science once you’ve seen it once. But the first time through, every single item on this list can eat half a day.