Unstripped Debug Symbols

iOS

Binary 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 = YES

2

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 end

3

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/Framework

Important: 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.

Bitrise logo