Cloud Builds · iOS
Compiling an iOS app has always meant macOS: Xcode is Mac-only, so React Native teams without a Mac either kept a macOS CI runner alive or borrowed a laptop every time the native side changed. Then came signing: a certificate exported from Keychain Access, a provisioning profile from the developer portal, and Transporter to get the result into TestFlight. VibeView cloud builds move every one of those steps off your machine.
This guide follows one app from source to TestFlight: a simulator build on a cloud iPhone first, then a signed .ipa, then the upload. It works the same from Windows, Linux or macOS, for bare React Native and Expo projects.
What you need
- A VibeView account and the CLI, 0.51.0 or later for build profiles:
npm install -g vibeview && vibeview login - A React Native project, bare or Expo (for a managed Expo project with no
ios/folder, Build an Expo app without EAS covers the prebuild details) - For the signed build and TestFlight: an Apple Developer Program membership and an App Store Connect API key (covered below)
You don’t need Xcode, CocoaPods or Ruby locally. Every plan includes cloud build minutes each month; builds are billed by the minute, and minutes beyond your plan’s allowance draw from usage credit. The pricing page has each plan’s numbers.
Part 1: a simulator build on a cloud iPhone
-
Start the build from your project root.
vibeview build --cloud --platform iosThe first run asks for two things and saves them to
vibeview.jsonas thedevelopmentprofile: the build command, and where the finished.applands. When the CLI can find your Xcode workspace, it suggests anxcodebuildcommand for the simulator. Make sure the command installs your dependencies first, becausenode_modulesandios/Podsare never uploaded. If you take the suggested command, the CLI also saves apreviewprofile, the same build in Release:{ "defaultPlatform": "ios", "platforms": { "ios": { "build": { "profiles": { "development": { "command": "yarn install --immutable && cd ios && pod install && cd .. && xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build CODE_SIGN_IDENTITY=-", "artifact": "ios/build/Build/Products/Debug-iphonesimulator/*.app" }, "preview": { "command": "yarn install --immutable && cd ios && pod install && cd .. && xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Release -sdk iphonesimulator -derivedDataPath ios/build CODE_SIGN_IDENTITY=-", "artifact": "ios/build/Build/Products/Release-iphonesimulator/*.app" } } } } } }The development build loads its JavaScript from Metro, which is what
vibeview devwants. The preview build has the JavaScript inside and runs by itself, so it’s the one to share or test; build it withvibeview build --cloud --platform ios --profile preview.Use whatever your lockfile calls for:
npm ci,yarn install --immutable(Yarn 1:yarn install --frozen-lockfilewith"packageManager": "yarn@1.x"inpackage.json, ornpx --yes yarn@1 install --frozen-lockfilewithout it),pnpm install --frozen-lockfileorbun install. -
Watch the log. The CLI packs every file git tracks plus untracked files that
.gitignoredoesn’t exclude, uploads them, and streams the build output. The log opens with the Xcode and iOS SDK versions your app is compiled against. Add--no-waitto start the build and leave;vibeview builds logs <id> --followpicks it back up. -
Run it. A succeeded simulator build lands in the app’s Build history with a
cloudbadge. If the project had no app yet, the build creates one from the binary and the CLI writes itsappIdintovibeview.json. Open the build’s page and choose Run this build to start it on a cloud iPhone in the browser, or runvibeview dev --platform iosto work on it with Metro and hot reload.
You’ll know it worked when the build page shows added to app builds on its timeline and the app launches on the simulator. From here it’s the normal VibeView loop: share the build as a link with someone who has no Mac, run your recorded tests against it, or hand the device to your coding agent. For a share link or a test run, use the preview build: it works without Metro running. Sharing without TestFlight covers the link.
Part 2: a signed .ipa for the App Store
A production build is a different artifact with a different job. It is signed with your distribution certificate, it is meant for TestFlight and the App Store, and a simulator can’t install it. It shows up on the Builds page with a Download action instead of in Build history.
-
Store an App Store Connect API key. This is what lets VibeView create signing material and upload builds for your team, with no Apple ID password and no two-factor prompts. In App Store Connect, open Users and Access → Integrations, generate a team key with the App Manager or Admin role, note its Key ID and your Issuer ID, and download the
.p8file (Apple lets you download it once). Then:vibeview credentials asc-key add --key-id <KEY_ID> --issuer-id <ISSUER_ID> --file AuthKey_<KEY_ID>.p8 -
Generate the certificate and profile. One command replaces exporting a
.p12from Keychain Access and downloading a profile from the developer portal:vibeview credentials generate --platform ios --name release --app <app-id>VibeView creates an Apple Distribution certificate for your team (or reuses the one it made earlier), registers the app’s bundle id with Apple if needed, creates an App Store provisioning profile, and stores both as a signing credential. Already have your own signing files? Upload them instead; the
.p12password is prompted with hidden input:vibeview credentials add --platform ios --file cert.p12 --profile app.mobileprovision --app <app-id> -
Set manual signing on the app target. A build machine has no signed-in Apple ID, so Xcode’s automatic signing can’t work there; the app target has to sign manually with your team and profile. Setting it on the app target is safer than passing the profile on the
xcodebuildcommand line: in a CocoaPods project (which nearly every React Native app is) a command-line profile reaches every Pod target too, and some Pods reject it and fail the archive.- Expo or a prebuild workflow: a small config plugin writes manual signing onto the app target during prebuild, using the team and profile VibeView provides to the build. The Kitlist sample app has a working one in
plugins/. - Bare React Native: set
CODE_SIGN_STYLE = Manual, yourDEVELOPMENT_TEAMand thePROVISIONING_PROFILE_SPECIFIERon the app target’s Release configuration inios/MyApp.xcodeproj/project.pbxproj. That’s the usual setup for a project that already ships to the App Store; App Signing explains exactly what the archive step needs.
- Expo or a prebuild workflow: a small config plugin writes manual signing onto the app target during prebuild, using the team and profile VibeView provides to the build. The Kitlist sample app has a working one in
-
Turn on automatic build numbers. App Store Connect refuses an upload that reuses a build number. Set
autoIncrementon the production profile and every production build gets the next number from a counter VibeView keeps per app, passed to the build asVIBEVIEW_BUILD_NUMBER. Map it to your app’s build number once (how). Because an App Store Connect key is stored, the first number starts above the builds your app already has in App Store Connect. -
Build the release.
vibeview build --cloud --profile production --platform iosThe first run asks for the release command: an
xcodebuild archivefollowed by an export. Pass only the signing identity on the archive step, and the export options file VibeView writes from your profile on the export step. The CLI saves it as theproductionprofile, next to the other two (--productionis short for--profile production):{ "platforms": { "ios": { "appId": "my-app-abc123", "build": { "profiles": { "development": { "command": "...", "artifact": "ios/build/Build/Products/Debug-iphonesimulator/*.app" }, "preview": { "command": "...", "artifact": "ios/build/Build/Products/Release-iphonesimulator/*.app" }, "production": { "command": "yarn install --immutable && cd ios && pod install && cd .. && xcodebuild archive -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Release -archivePath ios/build/MyApp.xcarchive ${VIBEVIEW_CODE_SIGN_IDENTITY:+\"CODE_SIGN_IDENTITY=$VIBEVIEW_CODE_SIGN_IDENTITY\"} && xcodebuild -exportArchive -archivePath ios/build/MyApp.xcarchive -exportPath ios/build -exportOptionsPlist \"$VIBEVIEW_EXPORT_OPTIONS_PLIST\"", "artifact": "ios/build/*.ipa", "autoIncrement": true } } } } } }Keep the quotes inside
${...:+"..."}: the identity name contains spaces, and without themxcodebuildsplits it into separate arguments.vibeview builds download <id>saves the.ipalocally if you want the file itself.
Part 3: upload the .ipa to TestFlight
Apple only accepts uploads for an app that already exists in App Store Connect, so create the record once: My Apps → + → New App, platform iOS, and the bundle id your build is signed with. If VibeView generated your credentials, it already registered that bundle id with Apple, so it’s in the list. Then check that Apple knows the app before you spend a build on it:
vibeview submit --check --platform ios --bundle-id com.example.myapp
And upload it, straight to a group of testers:
vibeview submit --platform ios --latest --group "QA team" --what-to-test "First TestFlight build"
--latest picks your newest succeeded production build. --group names a TestFlight group as it is called in App Store Connect. --what-to-test is the note its testers see. Both need CLI 0.55.0 or later; leave them out to upload without testers. Apple processes the build first. VibeView then answers export compliance, writes your notes to the build and puts it in your group. An external group goes through Apple’s Beta App Review before its testers get the build. If neither your Info.plist nor an earlier submission answered Apple’s encryption question, pass --no-uses-encryption (or --uses-encryption). App Store review, the store listing and screenshots stay in App Store Connect. Eligible builds also get a Submit to store button on the dashboard’s Builds page. Upload to TestFlight without a Mac goes deeper on this step.
Troubleshooting
- The archive fails with “does not support provisioning profiles”. A profile reached the Pod targets through the command line. Move manual signing onto the app target (step 3 of Part 2) and keep only
CODE_SIGN_IDENTITYon the archive command. - The archive fails asking for a signing certificate or development team. The app target is still on automatic signing. Set manual signing as in step 3.
Cannot find moduleor a missing Pods error early in the build. The build command didn’t install dependencies. Add the install step andpod install.- Apple refuses a duplicate build number. Turn on
autoIncrement, or seed the counter once withvibeview versions set --app <app-id> --platform ios <number>. - The build succeeds but says it can’t run on VibeView devices. The command produced a device build instead of a simulator one. Check that the simulator command passes
-sdk iphonesimulator.
Frequently asked questions
Do I need a Mac at any point?
No. The compile, the signing and the TestFlight upload all run on VibeView’s side; you run CLI commands from Windows, Linux or macOS. You do need an Apple Developer Program membership to sign and publish, the same as with a Mac.
Which Xcode version do cloud builds use?
Xcode 26.5, unless you add "xcode": "27.1" to the iOS build block (or pass --xcode 27.1) for
the iOS 27 SDK; apps built with it must use the scene-based life cycle (UIScene) to launch on
iOS 27. Beta Xcode versions aren’t offered, and App Store Connect doesn’t accept apps built with
them anyway. The build log prints the Xcode and iOS SDK versions. See Which Xcode iOS builds
use.
Can I run the signed .ipa on a VibeView simulator?
No. An .ipa is a device build, and simulators can’t install it. Check your change on the
preview build from Part 1, then ship the production build.
Does this work for an Apple TV app?
Yes. tvOS builds use the same commands with --platform tvos and a tvOS provisioning profile.
Build an Apple TV app without a Mac walks through it.
Can my coding agent run these builds?
Yes. The commands are the same, --json emits machine-readable build events, and the Builds
page gives you a ready-made prompt for Claude Code, Codex or Cursor that sets up the build
profiles and starts the builds. An AI agent shipped an Expo app to TestFlight in 43
minutes shows a full run.
Next steps
- Not using React Native? Flutter, Capacitor and Ionic and Kotlin Multiplatform projects cloud-build the same way, and so do native Xcode and Gradle projects
- Cloud Builds: every option in the build block, including build variables and secrets
- App Signing & Production Builds: uploading versus generating credentials, expiry and rotation
- Store Submission: the TestFlight and Google Play details
- Build a React Native Android app in the cloud: the same path for Google Play
Related guides
- Upload to TestFlight without a Mac
- Build a React Native Android app in the cloud
- Build an Expo app without EAS
- iOS simulator on Windows and Xcode for Windows: 2026 options
- React Native iOS simulator on Windows, with hot reload
- Build a Flutter iOS and Android app without a Mac
- Build a native iOS app without a Mac, plus Android
In the documentation
Try it yourself
Open a live iOS simulator, Android emulator, Apple TV, Android TV or Roku in your browser.
Start free