RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-05-05Intermediate

Rork EAS Build Profile Switching Gone Wrong — Fixing development, preview, and production Pitfalls

Troubleshoot common EAS Build profile mistakes in Rork Max — environment variable misconfig, uploading development builds to TestFlight, hitting dev APIs in production, and more. Practical fixes for each symptom.

Rork515EAS Build14build profileenvironment variables2Rork Max229troubleshooting65development2production4

"I pushed my app to TestFlight and realized it was still calling the development API in production" — if you've been building with Rork Max for a while, there's a good chance you've run into something like this. I once nearly shipped an app to the App Store where Stripe was still running in sandbox mode, all because I'd built with the wrong EAS profile.

EAS Build profiles are unavoidable when shipping native apps with Rork Max. But if you treat them as an afterthought, you're setting yourself up for a painful discovery right before launch. This article walks through the most common profile-switching problems, symptom by symptom, with concrete fixes you can apply today.

What makes EAS profile issues particularly tricky in Rork projects is that Rork's AI generates code and configuration automatically. That's a huge productivity win, but it means you might not have a deep understanding of how environment variables, native permissions, or signing credentials are wired together. When something breaks, it's not always obvious whether the issue is in the code Rork generated or in how you configured EAS. The breakdown below is organized around the symptoms you'll actually see, not the underlying technical concepts.

Understanding What Each EAS Build Profile Actually Does

Let's start by clarifying what each profile in eas.json is for — because they're surprisingly easy to mix up.

// eas.json — default config generated by Rork Max
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {
      "distribution": "store"
    }
  }
}

Here's how to think about each one:

  • development: Includes Expo's development client, which lets you use the debugger and hot reload. This build type cannot be submitted to the App Store — Apple will reject it at upload.
  • preview: Designed for TestFlight and internal distribution. Behaves close to production but can be distributed without App Store review.
  • production: What you submit to the App Store or Google Play. Optimized, stripped of dev tooling, and the only type you should ever send for review.

The critical detail is developmentClient: true. When that's present, Expo's development client is bundled into your app, significantly inflating the binary size and making it ineligible for store submission. Even if your app looks identical across all three profiles, the internals are quite different.

Problem 1: Environment Variables Aren't Reflecting the Right Profile

"I built with EAS and the API endpoint is still pointing at dev" — this is the most common profile-related issue I hear about.

The problem is usually that eas.json doesn't have explicit env definitions per profile, so the build falls back to whatever's in your local .env file. The fix is to be explicit about each environment.

// eas.json — define environment variables per profile
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "env": {
        "APP_ENV": "development",
        "EXPO_PUBLIC_API_URL": "https://dev-api.yourapp.com"
      }
    },
    "preview": {
      "distribution": "internal",
      "env": {
        "APP_ENV": "preview",
        "EXPO_PUBLIC_API_URL": "https://staging-api.yourapp.com"
      }
    },
    "production": {
      "distribution": "store",
      "env": {
        "APP_ENV": "production",
        "EXPO_PUBLIC_API_URL": "https://api.yourapp.com"
      }
    }
  }
}

Variables prefixed with EXPO_PUBLIC_ are accessible client-side, but they're statically embedded at build time — changing them after a build does nothing until you rebuild. To verify which profile a build was compiled with, temporarily render process.env.APP_ENV somewhere visible in your app UI. It's a sanity check that takes thirty seconds and saves a lot of confusion.

Problem 2: Production Build Is Using Stripe Test Keys

If users report that charges aren't going through after launch, check whether your production build is still using pk_test_ Stripe keys. This happens when API keys get hardcoded in Rork-generated source code, or when .env values bleed into the wrong build profile.

The right approach is to keep secrets out of eas.json and your source entirely. Use EAS Secrets instead.

# Register production Stripe keys as EAS Secrets
eas secret:create --scope project --name STRIPE_PUBLISHABLE_KEY --value pk_live_YOUR_KEY
eas secret:create --scope project --name STRIPE_SECRET_KEY --value sk_live_YOUR_KEY

EAS Secrets are injected as environment variables at build time, so your team never handles production credentials locally. When reviewing Rork-generated code, always search for pk_test_ or sk_test_ before building for production. It's a quick grep that's worth running every time.

Problem 3: You Uploaded a Development Build to TestFlight

ERROR: Invalid Binary
The binary you uploaded was built for development use only.

This error means you sent a development profile build to App Store Connect. The fix: rebuild with the right profile.

# For TestFlight (internal distribution)
eas build --platform ios --profile preview
 
# For App Store submission
eas build --platform ios --profile production

After the build finishes, check your EAS dashboard to confirm distribution shows Internal or Store before submitting. It takes a minute, but it's faster than waiting through an unnecessary rejection cycle.

One way to prevent this: configure a separate app icon tint or add the suffix "(Dev)" to your app name in the development env, so you can instantly tell which build is installed on your device. When your home screen shows two separate app icons — one labeled "MyApp" and one labeled "MyApp (Dev)" — you'll never accidentally submit the wrong one.

Problem 4: Confusing EAS Build with EAS Update

This distinction trips up a lot of Rork developers who discover OTA updates and start relying on them heavily.

  • EAS Build (eas build) — generates a full native binary (IPA/APK). Required any time native code or configuration changes.
  • EAS Update (eas update) — pushes a new JavaScript bundle over the air. Fast, but only captures JS-layer changes.

If Rork's AI added a native module — camera, push notifications, biometrics — or if you changed permissions in app.json, an EAS Update won't pick those up. You need a full rebuild. The typical symptom: your OTA update goes out, but the new feature simply doesn't appear for users on existing builds.

When in doubt: rebuild if anything changed in app.json, package.json, or any native configuration file.

Problem 5: Only Testing in Rork Companion, Not a Real Build

Rork Companion is great for rapid iteration, but it doesn't fully replicate what a standalone EAS build does on a user's device. Common areas that behave differently:

  • Camera, microphone, location: Companion shares Expo's permissions. Your standalone app needs them declared in app.json.
  • Push notifications: Companion uses its own push token, separate from your app's Expo token.
  • Deep links: Companion uses Expo's URL scheme. Your app uses the custom scheme you configured.
  • Native modules not bundled with Expo Go: These simply won't work in Companion.

Before any public release — TestFlight or store — do a final walkthrough on an actual preview build installed directly on a physical device. Rork Companion speeds up development significantly, but it's not a substitute for testing the artifact you're actually shipping.

Pre-Production Checklist

Before triggering a production build, run through these quickly:

  • [ ] EXPO_PUBLIC_API_URL in the production env points to your real backend, not a dev URL
  • [ ] No pk_test_ or sk_test_ Stripe keys exist anywhere in source code
  • [ ] app.json has the correct production bundle ID and version number incremented
  • [ ] All required permissions (camera, location, notifications) are declared in app.json
  • [ ] Signing credentials are configured for the production profile in EAS
  • [ ] You've tested the preview build on a real device, not just in Rork Companion

It takes about two minutes to go through this list. It's saved me from more than one embarrassing post-launch fix.

Commands Worth Knowing

# Review build history — see which profile built what
eas build:list
 
# List all registered EAS Secrets
eas secret:list
 
# Confirm your EAS configuration is valid
eas build:configure

eas build:list is underused. It shows your complete build history with profile names, so when a tester reports odd behavior you can quickly look up exactly what version they have installed.

The Setup That Makes Profile Mistakes Hard to Make

Most profile-switching errors happen because development and production builds look identical once installed. The most effective fix: give the development build a distinct bundle identifier.

// eas.json — separate bundle IDs for dev vs. production
{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "bundleIdentifier": "com.yourapp.dev"
      },
      "android": {
        "applicationId": "com.yourapp.dev"
      }
    }
  }
}

With a separate bundle ID, development and production install as independent apps on your device. You can run both simultaneously, and there's no risk of confusing which is which. It's a small change that eliminates a whole category of mix-up.

If you take one thing from this article: add explicit env values to each profile in eas.json. That single change prevents the majority of profile-related issues that come up in Rork Max projects. Once that's in place, the pre-production checklist above becomes a quick confidence check rather than a source of anxiety.

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.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-04-09
Rork Max EAS Build and App Store Submission Errors: Complete Troubleshooting Guide
Solve every error blocking your Rork Max app from reaching the App Store—code signing failures, expired certificates, ITMS upload errors, and App Store review rejections—with step-by-step fixes and commands.
Dev Tools2026-03-29
Resolving Rork App Build Errors with a Systematic Approach
Master Rork build errors: dependency conflicts, CocoaPods, Gradle, TypeScript, and Metro bundler issues. Complete troubleshooting guide with step-by-step solutions.
Dev Tools2026-07-17
The Update That Failed Because a Profile Expired Three Months Ago
Apple signing assets expire quietly and nothing tells you. Here is how to count the days left with the App Store Connect API and put the audit on a weekly Cloudflare Workers cron.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →