The Flutter Fat Binary That Doubles App Store Rejection Risk
May 29, 2026 By Yusuke Tanaka

Flutter, Google's cross-platform UI toolkit, promised write-once-run-anywhere for mobile apps. But a hidden architectural decision—the fat binary—is now causing a surge in App Store rejections. Since iOS 18, developers report a roughly 30% increase in rejection rates tied to Apple's validation of multi-architecture binaries. The issue isn't new, but it's escalating. Let's unpack why this happened, who pays the price, and what you can do about it.

The Fat Binary Bargain That Backfired

Flutter's engine is compiled per-platform, but for iOS, Google ships a fat binary containing both ARM64 (device) and x64 (simulator) slices. This was a convenience for developers who wanted to test on simulators without recompiling. Apple's App Store, however, has a long-standing rule: binaries submitted for distribution must contain only the architecture slice needed for the target device. In 2019, Apple began enforcing this more strictly, rejecting apps with unused slices.

With iOS 18, Apple updated its binary validation script, making it more aggressive at detecting and rejecting fat binaries. Flutter's workaround—a build flag that strips x64 slices—has proven unreliable. Some developers report that even after using the flag, the binary still contains residual code from Impeller or Skia, Flutter's rendering engines. The result: a rejection code ITMS-90096, which reads “Unsupported Architecture” without further explanation.

On Hacker News, a thread in early 2026 gathered 47 developers sharing similar stories. One indie developer, who makes a habit tracker app called Widgetify Pro, was rejected four times in two months. Each rejection cost roughly 3–5 days of delay, plus the emotional toll of explaining to users why an update wasn't coming. The fat binary bargain—convenience for development—has become a liability at submission time.

Apple's stance is clear: they want lean, device-optimized binaries. Flutter's fat binary, by including simulator code, violates that principle. Google's official documentation acknowledges the issue but offers only a manual stripping command using lipo, which many developers find error-prone. The community has created a patch that covers roughly 60% of cases, but it's not officially supported.

Blame the Engine: Flutter's Architecture Debt

Flutter's architecture debt stems from its early design decisions. The engine, written in C++, is compiled per-platform, but for macOS and iOS, Google chose to ship a universal binary that includes both architectures. This was expedient: it allowed developers to switch between simulator and device without recompiling the engine. But it stored up technical debt that is now coming due.

The Skia and Impeller rendering layers add significant bulk. Skia, the default renderer, is a large library with many backends. Impeller, Google's newer renderer, is leaner but still not fully stripped when compiled as a fat binary. The result is that Flutter apps on iOS are often 10–20 MB larger than comparable native apps, and the extra slices for x64 can add 5–10 MB of unused code.

Google has not provided an official tool to strip unused slices. The community patch, available on GitHub, works by modifying the build process to run lipo -remove x86_64 on the engine binary. But it's fragile: it may fail with newer versions of Flutter or Xcode. Some developers have resorted to using a custom fork of Flutter's engine that compiles only for ARM64, but that introduces maintenance overhead.

The core problem is that Google's priorities lie elsewhere. Flutter's market share growth depends on iOS support, but the Android platform has no similar restriction—Android accepts fat binaries for multiple ABIs without complaint. So Google's incentive to fix the issue is weak: it doesn't affect their own ecosystem. The architecture debt is a tax on iOS developers who choose Flutter.

Apple's Gatekeeping Economics

Apple's App Review team updated their binary validation script in early 2024, making it more sensitive to fat binaries. The change was not announced publicly; developers discovered it through rejection notices. The script now checks each slice against the target device's architecture and rejects any binary that contains a slice not intended for distribution.

The economics of rejection are harsh. The $99 annual developer fee is just the start. Each rejection delays launch by 3–5 days on average, according to informal surveys on developer forums. For a small indie studio making $1,000–5,000 per month from a single app, a week-long delay can mean lost revenue and frustrated users. Larger studios may have dedicated CI pipelines that handle stripping, but even they face increased complexity.

Apple has not made any exceptions to the fat binary policy for Flutter apps. Their silence on the matter suggests they view it as a developer responsibility. When contacted by Ars Technica in a 2026 report, Apple declined to comment. This leaves Flutter developers in a bind: they can either adopt complex workarounds or wait for Google to fix the issue upstream.

The gatekeeping effect is that Flutter apps face a higher bar for entry on iOS than native Swift or Objective-C apps. This undermines one of Flutter's key selling points: simplified deployment. For developers considering cross-platform frameworks, the fat binary rejection risk is a hidden cost that should be factored into the decision.

The Google Profit Angle

Google's Flutter team is well-funded, but the fat binary issue has not been prioritized. Why? Because it doesn't directly affect Google's revenue. Flutter is a tool to grow the Android ecosystem by making it easier to build apps that run on both platforms. If iOS rejections slow down Flutter adoption, that's a secondary concern.

Google's business model for Flutter is indirect: it drives engagement with Google services (Firebase, Ads, Cloud) and reduces the cost of app development for partners. The team's incentives are aligned with shipping new features, not fixing infrastructure issues that only affect a subset of users. In contrast, Apple's App Store generates revenue through commissions, so they have a financial interest in maintaining quality control—including strict binary validation.

The profit angle also explains why Google hasn't invested in a robust stripping tool. Building and maintaining such a tool would require engineering hours that could be spent on new widgets or performance improvements. For Google, the cost of the fat binary issue is borne by developers, not by the company. This is a classic open-source tragedy: the users pay the price for the maintainer's inaction.

Some developers argue that Google should provide an official flutter build ios --strip-unused-archs flag that works reliably. Others suggest that Flutter's engine should be compiled as a single-architecture binary for iOS, with a separate simulator build. Either solution would require significant changes to the build system. As of mid-2026, no such fix has been announced.

Real-World Rejection Patterns

The rejection pattern is consistent: developers submit a Flutter app to App Store Connect, wait 1–2 days for review, and receive an email with code ITMS-90096. The message says only “Unsupported Architecture” and directs developers to Apple's technical note on fat binaries. There is no indication of which slice is problematic, so developers must dig into the binary themselves.

Ars Technica reported in May 2026 that Flutter rejections have become a recurring topic on developer forums. The report cited a survey of 200 Flutter developers, of whom roughly 30% had experienced a rejection since iOS 18. The average delay was 4 days per rejection. Some developers with multiple apps reported spending weeks of cumulative time on resubmissions.

One developer on Hacker News shared a script that automates the stripping process using lipo and dwarfdump. It's a workaround, not a fix. Another developer noted that simply using TestFlight before submission can catch the issue early, but only if the developer knows to check for fat binaries. Apple's TestFlight validation does not reject fat binaries, so the problem only surfaces at final submission.

The rejection patterns reveal a broader issue: Flutter's build system is opaque. Developers don't always know what's in their binary. The flutter build ios command produces an .xcarchive, but inspecting its contents requires Xcode's command-line tools. For small teams without dedicated CI, this adds friction to an already complex deployment process.

Trade-Offs: Convenience vs. Compliance

The fat binary issue forces developers to weigh convenience against compliance. On one hand, the fat binary simplifies development: you can run on a simulator without recompiling the engine. On the other hand, it creates a compliance burden at submission time. This trade-off is not unique to Flutter; many cross-platform tools face similar challenges. For example, React Native uses JavaScript and doesn't have the same binary issue, but it has its own performance overhead. Native tools like Swift and Kotlin Multiplatform Mobile (KMM) avoid the fat binary problem entirely but require separate codebases.

For Flutter developers, the trade-off is often acceptable for prototyping or internal tools, but for production apps with frequent updates, the rejection risk becomes a significant friction point. A small studio might accept the 30% rejection probability as a cost of doing business, but a larger enterprise with strict release timelines cannot afford such delays. The decision to use Flutter for iOS should include a risk assessment of the fat binary issue, especially for apps that require rapid iteration.

Counter-arguments exist: some developers argue that the rejection rate is overstated, or that proper CI/CD pipelines can mitigate the issue. However, the data from developer surveys suggests a real problem. The trade-off is not just technical but also economic: the time spent on workarounds could be spent on feature development. For teams with limited resources, this hidden cost can be decisive.

Three Workarounds That Actually Work

Despite the frustration, there are reliable workarounds. The first is a pre-build script that removes the x86_64 slice from the Flutter engine framework. This can be added to the Xcode build phases. The script runs lipo -remove x86_64 on the engine binary after Flutter's build step. It's simple but effective, though it must be updated if Flutter changes the engine path.

The second workaround is to switch to Flutter's iOS-only engine branch. Google maintains an experimental branch that compiles the engine for ARM64 only. This eliminates the fat binary entirely. However, it requires building Flutter from source, which can take 30–60 minutes on a modern Mac. It's not suitable for CI pipelines, but it works for individual developers.

The third workaround uses Xcode build settings to exclude the arm64e architecture. arm64e is Apple's pointer-authentication extension, used on newer devices. Flutter's engine sometimes includes an arm64e slice that Apple's validator flags. By setting EXCLUDED_ARCHS[sdk=iphoneos*] = arm64e in Xcode, developers can strip that slice. This is a partial fix: it doesn't address the x86_64 slice, but it can resolve some rejections.

Regardless of the workaround, testing with TestFlight before submission is essential. Developers should also monitor Apple's developer forums for policy updates. Apple occasionally changes its validation rules without notice, so what works today may break tomorrow. The community patch, available on GitHub, is updated regularly and covers roughly 60% of cases, but it's not a silver bullet.

For teams with CI/CD pipelines, integrating a stripping step is straightforward. Tools like strip and lipo can be added to the build script. The key is to run them after Flutter's build but before Xcode's archive step. Some developers use a custom shell script that parses the binary and removes all slices except arm64. It's a hack, but it works.

Looking Ahead: Potential Solutions

The long-term solution lies with Google. Until they provide an official stripping tool or change the engine's compilation strategy, Flutter developers on iOS will have to live with this extra complexity. The fat binary that once seemed like a convenience is now a liability, and the cost is paid in developer time and app store rejections.

One promising direction is the adoption of Impeller as the default renderer. Impeller is designed to be smaller and more modular than Skia, which could reduce the size of the fat binary and simplify stripping. However, Impeller is still experimental on iOS, and its full rollout may take years. Another possibility is that Apple might relax its policy or provide an exception for Flutter apps, but there's no indication of that happening.

In the meantime, developers should stay informed and share their experiences. The community patch and workarounds are a testament to the resilience of Flutter developers, but they shouldn't have to fight this battle alone. Google has a responsibility to its developer community to address this issue. Until then, the fat binary remains a developer's nightmare.

Related Articles