Unstripped Debug Symbols
iOSBinary contains debug symbol tables that inflate app size by 30-42%. Common after Xcode 14 removed automatic server-side stripping.
iOS binaries can contain multiple layers of debug information: function starts metadata, the nlist symbol table (especially large in Swift due to mangled names prefixed with _$s), and DWARF debug info. Even after dSYM extraction, binaries retain their symbol table and function starts data unless explicitly stripped for production.
Why this happens
Apple's deprecation of bitcode in Xcode 14 (September 2022) removed automatic server-side stripping. Apps that relied on this suddenly shipped with all symbols intact.
DEPLOYMENT_POSTPROCESSING defaults to NO. Without it set to YES, all other strip settings are silently ignored.
CocoaPods sets STRIP_INSTALLED_PRODUCT=NO at the project level (since 2011), so all CocoaPods-built dynamic frameworks ship unstripped unless overridden.
Vendored frameworks from third-party SDK vendors may not strip their pre-built binaries.
Using xcodebuild build instead of archive. Only archive automatically sets DEPLOYMENT_POSTPROCESSING=YES.
Size impact
Debug symbols typically inflate binary size by 30-42%. This is often the single largest optimization opportunity.
Nike
+127.3 MB (39.6% of total)
American Airlines
+76.2 MB (42%)
Chime
~50 MB (31%)
Intuit Suite (3 apps)
578 MB potential savings (42%)
How we detect it
Scans all Mach-O binaries in the app bundle and identifies those with HasDebugSymbols: true and DebugSymbolsSize > 0. Impact is measured directly from the debug symbol table size in the binary metadata.
How to fix
1
Set Xcode build settings (all required together)
These settings must all be enabled in your Release configuration. Missing any one of them can silently disable stripping.
Xcode Build Settings (Release)
DEPLOYMENT_POSTPROCESSING = YES
STRIP_INSTALLED_PRODUCT = YES
STRIP_STYLE = all # Use "non-global" for frameworks
COPY_PHASE_STRIP = YES
STRIP_SWIFT_SYMBOLS = YES2
Fix CocoaPods stripping
CocoaPods disables stripping at the project level. Add a post_install hook to re-enable it for Release builds.
Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
next unless config.name == 'Release'
config.build_settings['STRIP_INSTALLED_PRODUCT'] = 'YES'
end
end
end3
Strip vendored frameworks manually
For pre-built frameworks from third-party vendors, strip non-global symbols while preserving the public API.
strip -x Framework.framework/FrameworkImportant: Always generate dSYM files before stripping. Without matching dSYMs, crash reports cannot be symbolicated. Set "Debug Information Format" to "DWARF with dSYM File" for Release builds.
Powered by Bitrise, trusted by 8,500+ brands
Size Analyzer is built by Bitrise, the leading mobile DevOps platform used by over 400,000 developers at companies like Shopify, TripAdvisor, and BuzzFeed. Free forever. No signup required.
Bitrise provides a full-stack mobile DevOps solution that unites the tools, processes, and testing frameworks engineering teams need to ship best-in-class mobile experiences.