One codebase, both app stores

One Expo codebase ships to iOS and Android without a Mac maze or two separate builds. Here's the pipeline I use, and the one feature that lets me fix a bug without waiting on Apple.

PPrabir Singh·
·6 min read
Two smartphones displaying matching blue and cream app interfaces beside a laptop.

The old way to ship a mobile app was to build it twice. Swift for iOS, Kotlin for Android, two codebases drifting apart, and a Mac in the corner you needed just to make an iPhone build at all. Two of everything. Two bills.

I don't work that way, and I don't ask clients to pay for it. One Expo codebase goes to both stores. Here's the actual pipeline, and the one feature that means a bug fix doesn't have to sit in Apple's review queue for two days.

One codebase, or you pay for two

The app is Expo and React Native, written in the same TypeScript as the web. That's not a small detail. It means the validation, the types, and a chunk of the logic are shared with the web client through a package, so a change lands in both places at once. It's the same one-language argument I make for the whole stack, and it's loudest on mobile, where a second codebase is a second team you can't afford.

The client who asked for "an app version, later" is happy when later takes days, because the hard parts already exist. That only works if the phone speaks the same language as everything else.

EAS Build does the Mac maze so you don't

Here's the part that used to hurt. Building for iOS meant owning a Mac, installing Xcode, wrangling provisioning profiles and signing certificates by hand, and doing a parallel dance for Android. It was a day of setup before you shipped a single screen.

EAS Build moves that into the cloud. It builds both platforms on Expo's machines, manages the signing credentials for you, and hands back an installable binary. I don't need a Mac to make an iPhone build. The build recipe lives in one file, versioned with the code.

// eas.json
{
  "build": {
    "production": {
      "ios": { "autoIncrement": true },
      "android": { "autoIncrement": true }
    }
  }
}

One command per platform, or both at once, and the machine that hated you is now someone else's problem.

The pipeline, end to end

One source of truth. Full builds go through the stores. JS-only fixes take the shortcut over the air.

eas build makes the binaries, eas submit uploads them to App Store Connect and the Play Console, and eas update handles the shortcut in the next section.

EAS Update: fix a bug without asking Apple

This is the feature that changes how it feels to run a live app.

A store update is slow by nature. You submit, Apple reviews, and you wait. For a typo or a broken button, waiting two days is absurd. EAS Update lets me push JavaScript and asset changes straight to installed apps, over the air, no review queue. A user opens the app and quietly has the fix.

The rule that keeps you out of trouble: over-the-air updates cover the JavaScript layer, not the native one. Change a color, fix logic, adjust a screen, that ships instantly. Add a native module or a new permission, and you need a real build through the store again. Learn that line and OTA is a superpower. Ignore it and you'll ship an update that references native code the installed binary doesn't have.

The two stores are not twins

One codebase does not mean one identical destination. The stores have their own personalities, and pretending otherwise is how launches slip.

Apple's review is stricter and slower, and it will reject you for things Google never mentions: a permission you don't justify, a login flow it doesn't like, a screenshot that oversells. Google's review is faster and lighter, but its own quirks show up around background work and permissions.

Push notifications route differently under the hood, through APNs on iOS and FCM on Android, though Expo's notification layer papers over most of that. Plan for the review gap especially. When a client wants a hard launch date, iOS is the one that decides whether you hit it.

Where it still bites

I'll keep it honest. The first setup of credentials and store listings is genuinely fiddly, once per app, and worth doing carefully because it haunts you later if you rush it. Some native modules aren't in Expo's managed flow and need a config plugin or a development build, which is a step up in complexity. And Apple can reject you late, for reasons that feel arbitrary, which is why I never promise a store date I don't control.

None of that outweighs the win. One codebase, one language, two stores, and OTA for the small stuff. That's a solo builder shipping like a team.

Frequently asked questions

Do I actually not need a Mac?

Correct. EAS Build compiles the iOS app in the cloud and signs it for you. You need an Apple Developer account for the store, not a Mac on your desk.

Can I really share code with the web app?

Yes. Types, validation, and framework-agnostic logic live in a shared package that both the web and mobile clients import. UI is separate, because a phone doesn't render a <div>, but the expensive parts are shared.

How much faster is an over-the-air update than a store update?

An OTA update reaches users in minutes. A store review runs hours to a couple of days, longer on iOS. That gap is exactly why you keep fixes on the JavaScript side when you can.

Is Expo ready for a serious app?

Yes. The player app in the RacketMania build is Expo, shipping to both stores from one codebase, with real payments and real-time features. It holds up.

Ship once, land twice

Building a mobile app twice made sense when the tools forced it. They don't anymore. One Expo codebase, cloud builds that skip the Mac maze, and over-the-air fixes for everything short of native code. That's the setup I reach for, and it's most of why "we'll want an app too" stopped being a scary sentence.

If that's on your roadmap, here's how I approach mobile. Or just tell me what you're building and we'll figure out whether it wants an app at all.

ShareXLinkedIn
P

Prabir Singh

Full-stack engineer from Mumbai. Twenty years in sales, now I build products that sell. More about me or start a project.

Keep reading

Two concrete paths diverging around a modern building in afternoon light.
·6 min read

Next.js or TanStack Start

Two React full-stack frameworks, one decision. Here's how I actually choose between Next.js and TanStack Start, and the projects where each one wins.