iOS Binary Size Reduction
Use this skill for: Swift/Xcode apps where executable and package size are above target and size reduction must preserve app behavior, security, and startup quality.
0) Inputs
workspace_or_project: .xcworkspace (preferred) or .xcodeproj
scheme
configuration: Release (default)
risk_level: low | balanced | aggressive
size_budget_mb: optional target reduction threshold
min_gain_mb: minimum gain to keep a change (0.3 MB default)
slice_scope: all or explicit family/OS slices
1) Guardrails
- Never apply unsafe production runtime settings:
-Ounchecked, -enforce-exclusivity=unchecked, or equivalent safety suppression flags.
- Never remove
dSYM generation. Keep symbol upload and crash-symbolication verified.
- Do not merge app behavior changes (asset migration, reflection, feature gating) without passing functional gates.
- Use one risk tier at a time; revert immediately on gate failure.
- Before edits, pin environment metadata (
xcodebuild -version, swift --version, destination, git SHA) and rerun the baseline pipeline once as a no-op control.
- Capture and apply settings per target (for example: app target first, then extensions/widgets), not only project-level.
2) Baseline capture (required)
Before any mutation:
- Collect build settings snapshot:
SWIFT_OPTIMIZATION_LEVEL
SWIFT_COMPILATION_MODE
DEAD_CODE_STRIPPING
STRIP_INSTALLED_PRODUCT
STRIP_SWIFT_SYMBOLS
LD / linker flags (OTHER_LDFLAGS)
ASSETCATALOG_COMPILER_OPTIMIZATION
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES
SWIFT_REFLECTION_METADATA_LEVEL
LD_RUNPATH_SEARCH_PATHS
- Capture size baselines from clean Release archive:
ipa size, app bundle size
- Mach-O
__TEXT and section split (xcrun size -m)
- symbol table size, dSYM size
- symbolication check against one controlled crash sample
- Capture baseline quality/perf gates:
- cold launch time and memory peak
- targeted smoke suite pass/fail
- launch crash/no-signature regressions
- Record immutable environment metadata:
xcodebuild -version, swift --version
- build destination (
-destination)
- git
HEAD and clean/dirty state
- scheme/configuration and archive variant
- Use a reproducible baseline command template and reuse it verbatim for repeatability:
- Workspace:
xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -configuration Release -destination "$DESTINATION" -archivePath "$TMP_ARCHIVE" clean archive
- Project fallback:
xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration Release -destination "$DESTINATION" -archivePath "$TMP_ARCHIVE" clean archive
- Export:
xcodebuild -exportArchive -archivePath "$TMP_ARCHIVE" -exportPath "$TMP_IPA_PATH" -exportOptionsPlist "$EXPORT_OPTIONS"
3) Pass scheduler (default execution order)
Tier 1 — Conservative
Apply in sequence, keep all gates green.
- Run a deterministic Release-only pipeline only:
clean
archive (-configuration Release)
- fixed-name export of
ipa
- Compare only this Release archive pair against future Release artifacts; ignore Debug artifacts and ephemeral caches.
- Enable deterministic post-processing:
DEPLOYMENT_POSTPROCESSING = YES, STRIP_INSTALLED_PRODUCT = YES
STRIP_SWIFT_SYMBOLS = YES
DEAD_CODE_STRIPPING = YES
SWIFT_COMPILATION_MODE = WholeModule
- Remove unused localizations and legacy assets only with an explicit locale/asset inventory
ASSETCATALOG_COMPILER_OPTIMIZATION = space, prune unused scales/device families; spot-check touched UI flows visually
- Strip raster metadata (
STRIP_PNG_TEXT = YES) where legal/compliance requirements allow it
- Unembed or prune unnecessary resource-heavy bundles
Tier 2 — Performance/size tradeoff
Only enable if Tier 1 passes.
SWIFT_OPTIMIZATION_LEVEL = -Osize
- Enable
LLVM_LTO (incremental/partial first)
- Slice pruning: remove unused architectures
- Set
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO only when precomputed target deployment matrix remains valid (per platform/extension/device family).
- Dependency minimization pass (SPM/CocoaPods): remove unused targets/features/modules
- App-thinning report validation and variant-specific packaging checks
Tier 3 — Conditional / high risk
Enable only with explicit approval when constraints are still missed.
Required preconditions:
- Tier 1 and 2 must have passed two consecutive measured runs.
- Size delta trend must be stable (median repeat variance below configured noise floor).
SWIFT_REFLECTION_METADATA_LEVEL = without-names, then selective none
- Symbol export hardening (
GCC_SYMBOLS_PRIVATE_EXTERN, exported/unexported symbol map strategy)
- Remove aggressive linker retention flags (
-ObjC, -all_load) only after runtime validation
- Move optional heavy payload to on-demand/background assets strategy
- Framework split/restructuring or feature-module extraction where architecture allows
4) Technique catalogue with trade-off notes
P1: Release-only clean baseline control. Low risk, required for valid deltas.
P2: DEPLOYMENT_POSTPROCESSING and STRIP_INSTALLED_PRODUCT are deterministic, low-risk size wins.
P3: STRIP_SWIFT_SYMBOLS = YES reduces size and improves artifact hygiene; requires strict dSYM retention.
P4: DEAD_CODE_STRIPPING = YES gives medium-high size gain; low behavior risk with smoke tests.
P5: Whole-module compilation is strong for dead boundaries; compile time can increase.
P6: Localization pruning gives high ROI only with accurate usage inventory.
P7: Asset catalog optimization is often highest ROI among Tier 1 items; visual regressions possible.
P8: STRIP_PNG_TEXT = YES can improve size; preserve legal/compliance metadata.
P9: Resource bundle pruning is strong but UX-sensitive.
P10: -Osize is effective for binary shrink; potential hot-path performance regression.
P11: LLVM_LTO typically improves size/perf but increases toolchain CPU/time.
P12: Architecture pruning is deterministic if target matrix is validated.
P13: ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO lowers size where safe; verify all target configurations.
P14: Dependency minimization has high value-to-effort, but functional side-effect risk is highest here.
P15: App-thinning validation is low risk, high confidence for deployment compatibility.
P16: Reflection metadata reduction is substantial, may break dynamic reflection users.
- Validation checklist before and after enabling:
JSONDecoder/Decodable hot paths still roundtrip correctly
- plugin/discovery paths using runtime type lookup
Mirror and dynamic cast behavior
- serialization framework smoke paths (Codable/custom coders)
P17: Export map hardening improves security posture but can break external integrations.
P18: Removing -ObjC / -all_load is risky if runtime registration depends on it.
P19: On-demand payload can greatly reduce install size; adds runtime fetch and fallback complexity.
P20: Module/framework extraction improves long-term size/control but high refactor risk.
5) Security, quality, and performance comparison
- Security priority (best to worse): export hardening (
P17) → deterministic stripping (P3,P4) → architecture/asset changes (P12,P7) → optimization/link choices (P10,P11) → reflection and linkage edits (P16,P18).
- Quality priority (best): resource and dependency cleanup (
P6,P7,P14) → conservative compile/link toggles (P5,P10,P11) → reflection/payload changes (P16,P19).
- Perf priority (best):
P11 and controlled reflection tuning (P16) are often neutral to positive; P10 can hurt hot paths.
6) Required validation gates after every pass
- Size gate:
ipa, app bundle, __TEXT, and install-eligible slices compared against baseline.
- Functional gate: app launches + critical flows + startup path coverage.
- Stability gate: controlled crash samples must symbolicate with uploaded dSYM.
- Runtime gate: post-change launch and memory budgets respected.
- Security gate: signing, entitlements, and crash-reportability unchanged.
- Reversion gate: if actual gain <
min_gain_mb or any gate fails, revert only that pass.
Gate execution rule:
- Run each gate twice (or one warm-up + one measured run at minimum); use median or stable mean for gate decisions.
- If either run is outlier by configured noise floor, rerun once before failing pass.
Default per-pass budgets unless overridden:
- size gain threshold:
min_gain_mb (or 0.3MB)
- launch: +5% or +100ms
- memory peak: +10MB max
- critical flows: no regressions
- crash sample symbolication: 100%
7) Evaluation report format
Produce a single report per run containing:
run_id, xcode_version, swift_version, git_sha, destination, risk_level
run_started_at, run_ended_at, run_duration_seconds
- Baseline and final size rows (
ipa, app, __TEXT, symbol bytes, dSYM bytes)
- Per-pass table entries:
pass_id
settings_changed
size_delta_mb
cumulative_gain_mb
pass_started_at, pass_ended_at, pass_duration_seconds
pass_status (applied, reverted, skipped)
security_impact
quality_impact
performance_delta
gate_status
rollback
notes
- Rollback log
- Final recommendation + confidence
8) Exit criteria and next-step policy
- Stop on first pass with acceptable reduction while all gates pass.
- If still above target, continue next tier.
- For
low risk_level, never run P14 or above without explicit approval.
- For
balanced, stop at tier 2 unless explicitly authorized.
- For
aggressive, keep user-informed checkpoints before tier 3.
9) Minimal output JSON schema
{
"run_id": "ios-size-YYYYMMDD-###",
"xcode_version": "15.x",
"swift_version": "5.x",
"git_sha": "",
"destination": "",
"risk_level": "low|balanced|aggressive",
"run_started_at": "2026-03-03T12:00:00Z",
"run_ended_at": "2026-03-03T12:03:24Z",
"run_duration_seconds": 204,
"baseline": {
"ipa_mb": 0.0,
"app_mb": 0.0,
"text_section_mb": 0.0,
"symbols_mb": 0.0,
"dsym_mb": 0.0
},
"final": {
"ipa_mb": 0.0,
"app_mb": 0.0,
"text_section_mb": 0.0,
"symbols_mb": 0.0,
"dsym_mb": 0.0
},
"cumulative_gain_mb": 0.0,
"passes": [
{
"id": "P4",
"gain_mb": 0.0,
"settings_changed": ["DEAD_CODE_STRIPPING=YES"],
"size_delta_mb": 0.0,
"cumulative_gain_mb": 0.0,
"pass_started_at": "2026-03-03T12:01:00Z",
"pass_ended_at": "2026-03-03T12:01:42Z",
"pass_duration_seconds": 42,
"pass_status": "applied",
"security": "low|medium|high",
"quality": "low|medium|high",
"performance_delta": "improved|neutral|degraded",
"gate_status": "pass|fail",
"rollback": false,
"notes": "reason"
}
]
}
1---2name: ios-binary-size-reduction3description: Use when an iOS app binary/app package needs size reduction with risk-aware optimization, security-aware checks, and verifiable build/runtime evaluation so results are safe and repeatable.4---5
6# iOS Binary Size Reduction
7
8Use this skill for: Swift/Xcode apps where executable and package size are above target and size reduction must preserve app behavior, security, and startup quality.
9
10## 0) Inputs
11
12- `workspace_or_project`: `.xcworkspace` (preferred) or `.xcodeproj`
13- `scheme`
14- `configuration`: `Release` (default)
15- `risk_level`: `low | balanced | aggressive`
16- `size_budget_mb`: optional target reduction threshold
17- `min_gain_mb`: minimum gain to keep a change (`0.3` MB default)
18- `slice_scope`: `all` or explicit family/OS slices
19
20## 1) Guardrails
21
22- Never apply unsafe production runtime settings: `-Ounchecked`, `-enforce-exclusivity=unchecked`, or equivalent safety suppression flags.
23- Never remove `dSYM` generation. Keep symbol upload and crash-symbolication verified.
24- Do not merge app behavior changes (asset migration, reflection, feature gating) without passing functional gates.
25- Use one risk tier at a time; revert immediately on gate failure.
26- Before edits, pin environment metadata (`xcodebuild -version`, `swift --version`, destination, git SHA) and rerun the baseline pipeline once as a no-op control.
27- Capture and apply settings per target (for example: app target first, then extensions/widgets), not only project-level.
28
29## 2) Baseline capture (required)
30
31Before any mutation:
32
331. Collect build settings snapshot:
34 - `SWIFT_OPTIMIZATION_LEVEL`
35 - `SWIFT_COMPILATION_MODE`
36 - `DEAD_CODE_STRIPPING`
37 - `STRIP_INSTALLED_PRODUCT`
38 - `STRIP_SWIFT_SYMBOLS`
39 - `LD` / linker flags (`OTHER_LDFLAGS`)
40 - `ASSETCATALOG_COMPILER_OPTIMIZATION`
41 - `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES`
42 - `SWIFT_REFLECTION_METADATA_LEVEL`
43 - `LD_RUNPATH_SEARCH_PATHS`
442. Capture size baselines from clean Release archive:
45 - `ipa` size, app bundle size
46 - Mach-O `__TEXT` and section split (`xcrun size -m`)
47 - symbol table size, dSYM size
48 - symbolication check against one controlled crash sample
493. Capture baseline quality/perf gates:
50 - cold launch time and memory peak
51 - targeted smoke suite pass/fail
52 - launch crash/no-signature regressions
534. Record immutable environment metadata:
54 - `xcodebuild -version`, `swift --version`
55 - build destination (`-destination`)
56 - git `HEAD` and clean/dirty state
57 - scheme/configuration and archive variant
585. Use a reproducible baseline command template and reuse it verbatim for repeatability:
59 - Workspace:
60 `xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -configuration Release -destination "$DESTINATION" -archivePath "$TMP_ARCHIVE" clean archive`
61 - Project fallback:
62 `xcodebuild -project "$PROJECT" -scheme "$SCHEME" -configuration Release -destination "$DESTINATION" -archivePath "$TMP_ARCHIVE" clean archive`
63 - Export:
64 `xcodebuild -exportArchive -archivePath "$TMP_ARCHIVE" -exportPath "$TMP_IPA_PATH" -exportOptionsPlist "$EXPORT_OPTIONS"`
65
66## 3) Pass scheduler (default execution order)
67
68### Tier 1 — Conservative
69
70Apply in sequence, keep all gates green.
71
721. Run a deterministic Release-only pipeline only:
73 1) `clean`
74 2) `archive` (`-configuration Release`)
75 3) fixed-name export of `ipa`
76 - Compare only this Release archive pair against future Release artifacts; ignore Debug artifacts and ephemeral caches.
772. Enable deterministic post-processing: `DEPLOYMENT_POSTPROCESSING = YES`, `STRIP_INSTALLED_PRODUCT = YES`
783. `STRIP_SWIFT_SYMBOLS = YES`
794. `DEAD_CODE_STRIPPING = YES`
805. `SWIFT_COMPILATION_MODE = WholeModule`
816. Remove unused localizations and legacy assets only with an explicit locale/asset inventory
827. `ASSETCATALOG_COMPILER_OPTIMIZATION = space`, prune unused scales/device families; spot-check touched UI flows visually
838. Strip raster metadata (`STRIP_PNG_TEXT = YES`) where legal/compliance requirements allow it
849. Unembed or prune unnecessary resource-heavy bundles
85
86### Tier 2 — Performance/size tradeoff
87
88Only enable if Tier 1 passes.
89
9010. `SWIFT_OPTIMIZATION_LEVEL = -Osize`
9111. Enable `LLVM_LTO` (incremental/partial first)
9212. Slice pruning: remove unused architectures
9313. Set `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO` only when precomputed target deployment matrix remains valid (per platform/extension/device family).
9414. Dependency minimization pass (SPM/CocoaPods): remove unused targets/features/modules
9515. App-thinning report validation and variant-specific packaging checks
96
97### Tier 3 — Conditional / high risk
98
99Enable only with explicit approval when constraints are still missed.
100Required preconditions:
101- Tier 1 and 2 must have passed two consecutive measured runs.
102- Size delta trend must be stable (median repeat variance below configured noise floor).
103
10416. `SWIFT_REFLECTION_METADATA_LEVEL = without-names`, then selective `none`
10517. Symbol export hardening (`GCC_SYMBOLS_PRIVATE_EXTERN`, exported/unexported symbol map strategy)
10618. Remove aggressive linker retention flags (`-ObjC`, `-all_load`) only after runtime validation
10719. Move optional heavy payload to on-demand/background assets strategy
10820. Framework split/restructuring or feature-module extraction where architecture allows
109
110## 4) Technique catalogue with trade-off notes
111
112- `P1`: Release-only clean baseline control. Low risk, required for valid deltas.
113- `P2`: `DEPLOYMENT_POSTPROCESSING` and `STRIP_INSTALLED_PRODUCT` are deterministic, low-risk size wins.
114- `P3`: `STRIP_SWIFT_SYMBOLS = YES` reduces size and improves artifact hygiene; requires strict dSYM retention.
115- `P4`: `DEAD_CODE_STRIPPING = YES` gives medium-high size gain; low behavior risk with smoke tests.
116- `P5`: Whole-module compilation is strong for dead boundaries; compile time can increase.
117- `P6`: Localization pruning gives high ROI only with accurate usage inventory.
118- `P7`: Asset catalog optimization is often highest ROI among Tier 1 items; visual regressions possible.
119- `P8`: `STRIP_PNG_TEXT = YES` can improve size; preserve legal/compliance metadata.
120- `P9`: Resource bundle pruning is strong but UX-sensitive.
121- `P10`: `-Osize` is effective for binary shrink; potential hot-path performance regression.
122- `P11`: `LLVM_LTO` typically improves size/perf but increases toolchain CPU/time.
123- `P12`: Architecture pruning is deterministic if target matrix is validated.
124- `P13`: `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO` lowers size where safe; verify all target configurations.
125- `P14`: Dependency minimization has high value-to-effort, but functional side-effect risk is highest here.
126- `P15`: App-thinning validation is low risk, high confidence for deployment compatibility.
127- `P16`: Reflection metadata reduction is substantial, may break dynamic reflection users.
128 - Validation checklist before and after enabling:
129 - `JSONDecoder`/`Decodable` hot paths still roundtrip correctly
130 - plugin/discovery paths using runtime type lookup
131 - `Mirror` and dynamic cast behavior
132 - serialization framework smoke paths (Codable/custom coders)
133- `P17`: Export map hardening improves security posture but can break external integrations.
134- `P18`: Removing `-ObjC` / `-all_load` is risky if runtime registration depends on it.
135- `P19`: On-demand payload can greatly reduce install size; adds runtime fetch and fallback complexity.
136- `P20`: Module/framework extraction improves long-term size/control but high refactor risk.
137
138## 5) Security, quality, and performance comparison
139
140- **Security priority** (best to worse): export hardening (`P17`) → deterministic stripping (`P3`,`P4`) → architecture/asset changes (`P12`,`P7`) → optimization/link choices (`P10`,`P11`) → reflection and linkage edits (`P16`,`P18`).
141- **Quality priority** (best): resource and dependency cleanup (`P6`,`P7`,`P14`) → conservative compile/link toggles (`P5`,`P10`,`P11`) → reflection/payload changes (`P16`,`P19`).
142- **Perf priority** (best): `P11` and controlled reflection tuning (`P16`) are often neutral to positive; `P10` can hurt hot paths.
143
144## 6) Required validation gates after every pass
145
1461. Size gate: `ipa`, app bundle, `__TEXT`, and install-eligible slices compared against baseline.
1472. Functional gate: app launches + critical flows + startup path coverage.
1483. Stability gate: controlled crash samples must symbolicate with uploaded dSYM.
1494. Runtime gate: post-change launch and memory budgets respected.
1505. Security gate: signing, entitlements, and crash-reportability unchanged.
1516. Reversion gate: if actual gain < `min_gain_mb` or any gate fails, revert only that pass.
152
153Gate execution rule:
154- Run each gate twice (or one warm-up + one measured run at minimum); use median or stable mean for gate decisions.
155- If either run is outlier by configured noise floor, rerun once before failing pass.
156
157Default per-pass budgets unless overridden:
158- size gain threshold: `min_gain_mb` (or 0.3MB)
159- launch: +5% or +100ms
160- memory peak: +10MB max
161- critical flows: no regressions
162- crash sample symbolication: 100%
163
164## 7) Evaluation report format
165
166Produce a single report per run containing:
167
168- `run_id`, `xcode_version`, `swift_version`, `git_sha`, `destination`, `risk_level`
169- `run_started_at`, `run_ended_at`, `run_duration_seconds`
170- Baseline and final size rows (`ipa`, `app`, `__TEXT`, symbol bytes, dSYM bytes)
171- Per-pass table entries:
172 - `pass_id`
173 - `settings_changed`
174 - `size_delta_mb`
175 - `cumulative_gain_mb`
176 - `pass_started_at`, `pass_ended_at`, `pass_duration_seconds`
177 - `pass_status` (`applied`, `reverted`, `skipped`)
178 - `security_impact`
179 - `quality_impact`
180 - `performance_delta`
181 - `gate_status`
182 - `rollback`
183 - `notes`
184- Rollback log
185- Final recommendation + confidence
186
187## 8) Exit criteria and next-step policy
188
189- Stop on first pass with acceptable reduction while all gates pass.
190- If still above target, continue next tier.
191- For `low` risk_level, never run `P14` or above without explicit approval.
192- For `balanced`, stop at tier 2 unless explicitly authorized.
193- For `aggressive`, keep user-informed checkpoints before tier 3.
194
195## 9) Minimal output JSON schema
196
197```json
198{
199 "run_id": "ios-size-YYYYMMDD-###",
200 "xcode_version": "15.x",
201 "swift_version": "5.x",
202 "git_sha": "",
203 "destination": "",
204 "risk_level": "low|balanced|aggressive",
205 "run_started_at": "2026-03-03T12:00:00Z",
206 "run_ended_at": "2026-03-03T12:03:24Z",
207 "run_duration_seconds": 204,
208 "baseline": {
209 "ipa_mb": 0.0,
210 "app_mb": 0.0,
211 "text_section_mb": 0.0,
212 "symbols_mb": 0.0,
213 "dsym_mb": 0.0
214 },
215 "final": {
216 "ipa_mb": 0.0,
217 "app_mb": 0.0,
218 "text_section_mb": 0.0,
219 "symbols_mb": 0.0,
220 "dsym_mb": 0.0
221 },
222 "cumulative_gain_mb": 0.0,
223 "passes": [
224 {
225 "id": "P4",
226 "gain_mb": 0.0,
227 "settings_changed": ["DEAD_CODE_STRIPPING=YES"],
228 "size_delta_mb": 0.0,
229 "cumulative_gain_mb": 0.0,
230 "pass_started_at": "2026-03-03T12:01:00Z",
231 "pass_ended_at": "2026-03-03T12:01:42Z",
232 "pass_duration_seconds": 42,
233 "pass_status": "applied",
234 "security": "low|medium|high",
235 "quality": "low|medium|high",
236 "performance_delta": "improved|neutral|degraded",
237 "gate_status": "pass|fail",
238 "rollback": false,
239 "notes": "reason"
240 }
241 ]
242}
243```