Guide: How to Publish to App Store with Expo & React Native
Learn how to publish to app store for Expo & React Native in 2026! Our guide covers everything from EAS Build to passing review.

You've finished the product work. The app runs well in Expo Go, your flows feel stable, and the last thing standing between you and launch is Apple's publishing pipeline. That final stretch is where many React Native teams slow down, not because the code is hard, but because App Store submission mixes build tooling, metadata, compliance, and review rules in one place.
If you're using a modern Expo stack, the process is much cleaner than old Xcode-heavy guides make it sound. But clean doesn't mean forgiving. The mistakes that block launch are usually small, boring, and avoidable: the wrong bundle identifier, a weak privacy policy page, screenshots that don't match the current build, or subscription products left in the wrong state. This guide focuses on the workflow that suits an AppLighter-style Expo app, not a generic native iOS project.
Table of Contents
- From AppLighter to App Store The Publishing Roadmap
- Essential Prerequisites Before Your First Build
- Building Your App with Expo Application Services
- Uploading and Testing with TestFlight
- Finalizing Your App Store Listing
- Troubleshooting Common App Store Rejections
From AppLighter to App Store The Publishing Roadmap
The opportunity is big enough to justify getting the process right. The Apple App Store ecosystem reached $1.4 trillion in developer billings and sales globally in 2025, with 557,000 new app submissions in 2025 alone, according to Apple's newsroom summary of the Analysis Group study on the App Store ecosystem milestone. For indie teams and startup builders, that matters. It means you're publishing into a crowded market, but also a market where shipping still creates real upside.
For an Expo app, how to publish to App Store is less about wrestling Xcode and more about following a reliable sequence. Those who get stuck are trying to do pieces out of order. They build before locking the app identity, upload before testing on real devices, or submit before the App Store listing is consistent with the binary.
The practical roadmap looks like this:
- Create the Apple-side foundation. Developer account, App Store Connect app record, bundle identifier, privacy policy URL, and release assets.
- Build the iOS binary with EAS. Let Expo handle the cloud build and signing flow.
- Upload and process the build. Usually through
eas submit. - Run TestFlight properly. Real devices, real accounts, real edge cases.
- Finish the listing and submit for review. Metadata, screenshots, privacy disclosures, release settings.
- Handle feedback fast. If review flags something, answer narrowly and resubmit.
That sequence sounds simple because it is. The friction comes from the little details inside each step.
A release process also matters after your first launch. If you want a clean mental model for versioning, build promotion, and update discipline, this breakdown of a mobile app release management process is worth reading before you start publishing regularly.
One more practical point. Shipping the app is only one part of launch. If you're a startup trying to get early attention once the app is live, curated directories and launch channels can help improve startup visibility without turning your launch into a paid acquisition sprint on day one.
The teams that publish smoothly usually treat App Store release work like product work, not admin work.
Essential Prerequisites Before Your First Build
Friday afternoon is a bad time to discover your bundle ID is wrong, your privacy policy URL returns a 403 outside your country, and the App Store Connect record still does not exist. With AppLighter projects, those problems usually hurt more than the build itself because the Expo side is often the easy part.
A checklist infographic outlining six essential prerequisites for preparing a mobile application for the Apple App Store.
Lock down the identity first
App identity choices stick.
For an AppLighter app running on the modern Expo stack, I set these before the first production build and before adding any Apple-specific service in a hurry:
- Apple Developer membership is active. If the account is pending, expired, or enrolled under the wrong entity, release work stalls fast.
- The App Store Connect app record exists. Create it early so the naming, bundle ID, and platform settings are not being decided during upload.
- The bundle identifier is final. Use a reverse-domain ID tied to the product, not the starter project or a client placeholder.
- Device and OS support are deliberate. React Native teams must pay attention to compatibility across the iOS versions their users still run, especially if the app depends on camera, notifications, auth, or in-app purchases.
- Signing ownership is clear. EAS can manage a lot, but your team still needs to know who controls the Apple account, certificates, and app transfers.
The bundle ID deserves extra caution. In Expo, changing it late means revisiting push setup, associated domains, Sign in with Apple, and anything else tied to the app identifier. That cleanup is annoying in a plain React Native app and worse when a team assumes the starter kit defaults are safe to ship.
If signing still feels fuzzy, read this explanation of what code signing means in mobile app delivery. You do not need to master Apple's certificate model, but you do need enough context to spot a broken setup before EAS fails halfway through a release.
Prepare review assets before you need them
A first build often exposes metadata gaps that should have been handled earlier. Apple reviews the app binary, but it also reviews the public-facing details around it.
These are the assets worth preparing up front:
| Item | What Apple expects | Common mistake |
|---|---|---|
| App icon | 1024x1024px PNG with no transparency | Shipping an icon exported from Figma with transparency still enabled |
| Privacy policy URL | Publicly reachable, stable, and relevant to the app | Using a Notion page, test domain, or a link that fails outside your region |
| Support URL | A working page or contact destination | Pointing to a blank marketing site footer |
| App description draft | Plain description of what the app does | Overselling features that are missing from the current build |
| Screenshot plan | Current screens that match the submitted app | Reusing onboarding or paywall screens from an older branch |
The privacy policy URL causes more App Store churn than many native issues. I have seen technically sound Expo builds delayed because the legal page redirected badly on mobile, required login, or disappeared after a hosting change.
Use a domain your team controls. Open the URL on mobile data, on Wi-Fi, and from another region if your users are international. Then keep that link in your release checklist.
One more practical point for teams shipping regularly from AppLighter. If you are standardizing release prep, build promotion, and checks around metadata, these insights into automated deployments are useful once your manual process is stable.
Building Your App with Expo Application Services
If you're still considering whether to build locally in Xcode or use EAS Build, use EAS unless you have a very specific reason not to. For an Expo app, especially one built from a structured starter, that's the path with the fewest moving parts and the best chance of repeatable releases.
Why EAS Build is the right default
Classic Expo build workflows are no longer the center of gravity for production releases. EAS Build fits modern React Native delivery better because it handles credentials, cloud build environments, and native packaging in a way that scales once your app stops being a prototype.
That matters more with AppLighter-style projects because they usually ship with enough integrations that you don't want release day to depend on a perfectly configured local Mac. Cloud builds reduce “works on my machine” nonsense.
Use EAS Build when you want:
- Consistent build environments. Everyone on the team gets the same output path.
- Credential handling without manual ceremony. Expo can manage much of the signing flow.
- A cleaner path for native modules. Once your app moves beyond the simplest Expo setup, this matters.
- Repeatability. Shipping updates should feel operational, not fragile.
There's also a broader lesson here. Automation helps after your release path is stable. If you're thinking through when to automate build and deploy steps, this explainer on automated deployment pipelines is useful because it separates helpful automation from premature process.
Don't build a fancy release machine before you've shipped one clean release manually through the same path.
If you're newer to Expo itself, this Expo getting started guide is a solid refresher before you wire up release profiles.
The production profile that matters
Typically, the important configuration lives in eas.json. Keep it boring. A production profile should be explicit, stable, and tied to release behavior you understand.
A simple production setup typically does three things:
- Marks the profile for store distribution
- Uses the correct app version and build number strategy
- Builds the iOS binary for submission, not ad hoc testing
Your flow will usually look like this:
- Update app metadata in your Expo config
- Confirm the iOS bundle identifier matches Apple
- Check icons, splash assets, and environment variables
- Run the production build command
- Wait for the cloud build to complete and inspect the artifact
The command is straightforward:
- Run
eas build --platform iosfor the production binary
What matters isn't typing the command. It's what you verify before pressing Enter. For React Native apps, release builds expose things development mode can hide: missing environment variables, permissions that were never justified properly, production API behavior, and differences in navigation or deep linking.
A practical pre-build check for Expo teams:
- Environment variables. Make sure production values are present and not inherited accidentally from staging.
- Permissions. If your app asks for photos, camera, or microphone access, the reasons shown to users must be specific and consistent with real usage.
- Native config plugins. Review anything that changes
Info.plistor entitlements. - Versioning. Increment what needs to be incremented before upload.
- App icon and splash assets. Fix these early so the binary matches the store listing.
The best EAS setup is the one your future self can trust at 11 PM before a release.
Uploading and Testing with TestFlight
You finish the EAS build, submit it, and everything looks fine in the dashboard. Then the TestFlight build lands on a real iPhone and the first tester hits a broken password reset, a missing permission string, or a white screen after tapping a push notification. That is the part of release work that matters.
A six-step process diagram illustrating how to upload and test an application using Apple TestFlight.
Getting the build into TestFlight
For AppLighter projects on modern Expo, eas submit --platform ios is usually the right move. It keeps the handoff inside the EAS workflow and avoids the old pattern of exporting files and juggling manual uploads.
Transporter is still worth keeping around. I use it as a fallback when App Store Connect credentials are acting up, when a team account has unusual permission setup, or when Apple rejects the upload before processing starts. You probably will not need it often, but the day you need it, you will want it installed already.
After submission, App Store Connect still needs time to process the binary. Do not invite testers the second the upload finishes. Wait until the build is fully available, assign it to the right internal or external group, and confirm the release notes explain what changed. Good notes get better feedback.
A quick visual walkthrough helps if you haven't done the flow before:
What to test on a real device
TestFlight should be treated like a release gate for Expo apps, especially with AppLighter where a lot of setup is fast enough that teams can skip the last serious QA pass. That shortcut usually comes back as a review rejection or a bug report from the first users.
Start with the flows that break hardest outside development:
- Authentication. Email login, social login, magic links, password reset, account creation, sign out, account deletion.
- Fresh install behavior. First launch, onboarding, persisted session restore, empty states.
- Permissions. Notifications, camera, photos, microphone, location. Check both allow and deny paths.
- Payments. Subscription purchase, upgrade, downgrade, cancellation state, restore purchases.
- Links and routing. Universal links, password reset links, invite links, push notification taps.
- Device reality. Older iPhones, bad network conditions, dark mode, low battery mode, interrupted app sessions.
Expo apps have a few predictable weak spots here. Deep linking can behave differently in production than it did in Expo Go. Push notifications often fail because the production credentials were never tested end to end. Config plugin changes can also produce native behavior you never saw during local development.
The gotchas that waste the most time
Internal testers are for fast validation. External testers are better for catching language, onboarding, and edge-case behavior because they approach the app without context. Use both.
For AppLighter apps, I usually check four things before sending an external group live:
- The correct API environment is active
- The bundle in TestFlight matches the latest backend schema
- Any feature flags are set the way production expects
- The support contact inside App Store Connect is real and monitored
One more practical detail. Screenshots shown to testers and later submitted to the store should reflect the actual release build, not development placeholders. If you need a stronger process for that, this guide on designing effective app screenshots is useful.
A weak TestFlight round creates slow, expensive cleanup work. A disciplined one catches the problems Apple reviewers notice fast, and the problems users punish even faster.
Finalizing Your App Store Listing
Friday evening is a bad time to discover your release build is ready but your store listing still has placeholder copy, a broken support URL, and screenshots from an older branch. For AppLighter teams using Expo EAS, that is a common last-mile failure. The JavaScript is done, the binary is in App Store Connect, and the submission still stalls on assets and metadata.
An infographic chart outlining the essential components required for finalizing an App Store listing for developers.
Metadata that matches the shipped app
The listing has to describe the build Apple reviews, not the roadmap in your head. That matters even more with AppLighter projects, because it is easy to ship fast with Expo and forget that App Store metadata gets reviewed against the actual product.
Start with the fields that create the most review friction when they are sloppy:
- App name. Clear, distinct, and close to what users will search for.
- Subtitle. One concrete value proposition, not a slogan.
- Description. Explain what the app does in plain language, then cover the first actions a new user can take.
- Keywords. Relevant terms only. Stuffing them usually weakens discoverability and makes the listing look amateur.
- Primary category. Pick the shelf users would browse.
- Support URL and marketing URL. Both should load on mobile, without redirects to dead pages or unfinished templates.
- Age rating questionnaire. Answer it against the in-app content, not the intended audience.
For Expo apps, consistency matters more than clever wording. If your listing says users can sign in with Apple, use offline mode, or receive push alerts, the release build should already support that flow in production.
The icon setup is another easy place to lose time. Upload a clean 1024 by 1024 PNG, with no transparency and no rounded corners. Apple handles the masking. I also recommend checking the icon against dark and light backgrounds before upload. AppLighter founders often spend days refining onboarding, then submit an icon that looks muddy at small sizes.
Screenshots carry more weight than developers usually expect. They set user expectations before install, and they also expose mismatches between your listing and your shipped build. If you want a practical design perspective, this guide on designing effective app screenshots is worth reviewing before you export your final set.
Release settings that save cleanup work
App Store Connect includes a few release controls that are easy to ignore until you need them.
| Setting | Why it matters | When to use it |
|---|---|---|
| Pre-order | Lets you collect interest before launch | Planned releases with a real launch date |
| Phased Release | Reduces risk when pushing an update | Bigger UI changes, pricing changes, or native config changes |
| App Analytics | Shows acquisition and retention trends after launch | Every production app |
For AppLighter apps, Phased Release is the one I use most often after launch. Expo updates can move fast, but not every change should hit everyone at once. If a release includes a new config plugin, subscription flow changes, or auth updates, roll it out gradually so you can catch production issues before they affect the whole install base.
Pre-orders only help if the rest of the launch plan is real. If your landing page, onboarding, backend capacity, and support channel are still in motion, skip the vanity of a launch date and finish the product work first.
One final check pays for itself. Read the listing once from the perspective of a reviewer and once from the perspective of a first-time user. Reviewers look for accuracy. Users look for clarity. If either group sees promises the app does not keep, you create avoidable risk.
Troubleshooting Common App Store Rejections
Rejection feels personal the first time. It usually isn't. Apple is checking compliance and completeness, and first submissions get tripped up by a small set of recurring issues.
A chart showing common Apple App Store rejection reasons and their corresponding solutions for mobile developers.
The rejections that hit first-time submissions most often
The main pattern is simple. Non-compliance causes more trouble than technical difficulty.
According to SuperAppp, 25–30% of first-time submissions are rejected, and the most frequent causes are “inapp” functionality at 18%, missing or inaccessible privacy policy URLs at 12%, and insufficient permission justifications at 9% in its breakdown of how difficult App Store publishing is.
For Expo and React Native apps, these are the rejection classes I'd watch closest:
- Website-wrapper perception. If the app feels like a thin webview with little native value, review may push back on minimum functionality.
- Privacy policy accessibility. The URL exists, but Apple can't access it consistently, or the page doesn't disclose what the app does.
- Weak permission copy. Camera, photos, microphone, or notifications are requested without clear user-facing reasons.
- Subscription product readiness. Products exist in App Store Connect, but they aren't fully ready for submission.
- Metadata mismatch. The store page promises something the binary doesn't support.
The privacy policy issue is more nuanced than most guides admit. A later data point highlighted that 28% of rejections for new apps were due to privacy policy accessibility or missing disclosures in Apple's 2025 App Review communications, as discussed in this video analysis of privacy policy URL accessibility failures. That tracks with what indie teams run into. The link works in one country, fails in another, or sits behind a setup that looked “good enough” until review.
Subscription apps have their own trap. A separate 2025-focused analysis reports that 34% of new subscription apps were rejected for purchase product readiness or pricing mismatch issues in Apple's Q3 review data, in this write-up on submission problems caused by mismatched purchase states. If your product depends on subscriptions, verify every product is ready before you submit the binary.
How to fix the rejection without thrashing
A rejection message usually tells you more than people think. Read it as written first. Don't jump straight into broad refactors.
Use this response pattern:
- Identify the exact guideline or complaint
- Reproduce the issue on a production-like build
- Fix only the rejected surface first
- Reply in App Store Connect with a direct explanation
- Resubmit with notes if the fix isn't obvious from the UI
For common rejection types, the practical fixes look like this:
- If Apple says the app lacks functionality: make the native experience visible. Explain offline support, push notifications, device integration, camera usage, or other app-native behavior if those features exist.
- If the privacy policy is inaccessible: move it to a stable public host, remove login requirements, and verify it loads cleanly from multiple locations.
- If permissions are unclear: rewrite the usage descriptions to match the exact user action that triggers them.
- If subscriptions are not ready: check every product state in App Store Connect and resolve incomplete pricing, descriptions, or localization issues before the next submission.
- If metadata is misleading: update the listing to describe the shipping build, not the roadmap.
Most review fixes are smaller than they feel on rejection day.
A lot of teams waste time by over-correcting. They rebuild large chunks of the app when Apple asked for one missing explanation, one broken URL, or one incomplete commerce setting. Handle the specific issue first, then decide whether broader cleanup is worth doing.
If you want to ship faster without rebuilding the same Expo plumbing every time, AppLighter gives you a production-ready mobile app starter with the core pieces already wired up, so you can spend more time on product and less time on setup, build friction, and release prep.