Mac 開発者がターミナルで Xcode DerivedData のディスク使用量を調査

午前2時、CI パイプラインからアラート:ビルドノードのディスク残量が 2 GB 未満、xcodebuild が直接終了。ターミナルを開き df -h を確認すると、256 GB の SSD が満杯——~/Library/Developer ディレクトリだけで 180 GB を占有し、その中の DerivedData だけで 90 GB 以上。

これは偶発的な事故ではありません。8か月間クリーンアップなしで稼働した M4 Mac Mini では、DerivedData が平均 40–100 GB 蓄積します。シミュレータイメージやデバイスシンボル表を加えると、~/Library/Developer の合計が 150 GB を超えることも珍しくありません。本記事では根本原因分析→素早い特定→分類別対処→CI 防塞→自動メンテナンスの5段階で、そのまま使える運用手順を提供します。

読み終えると得られるもの:DerivedData 各サブディレクトリの実際の用途と安全性評価、最大ディスク占有源を特定する1コマンド、CI/ローカル両シナリオのクリーンアップスクリプト、ディスク警告を二度と発生させない自動化方案です。

Quick Answer:最もよくある3つの質問

質問 直接の答え リスク
DerivedData は直接削除できますか? rm -rf ~/Library/Developer/Xcode/DerivedData/* は完全に安全 次回ビルドがフルビルドになり、約2–5分増加
Archives は削除できますか? オンラインユーザーがいないバージョンは削除可;現行バージョンは dSYM を保持 削除後、旧バージョンのクラッシュログをシンボル化不可
CI ノードのディスクが逼迫したときの緊急対処は? DerivedData → シミュレータ unavailable → 旧版 DeviceSupport の順にクリーンアップ 次回ビルドでインデックス再構築が必要、約3分遅くなる

DerivedData には何が保存されているか

多くの開発者は「DerivedData をクリアすれば謎の問題が解決する」と知っていますが、中身を理解していないと、削除すべきでないものを消したり、消すべきものを残してディスクを何度も逼迫させたりします。以下は ~/Library/Developer 下の最重要パスです:

パス 内容 典型的なサイズ 安全に削除?
Xcode/DerivedData ビルド成果物、インデックス、ビルドログ、Swift モジュールキャッシュ 5–60 GB ✅ 完全に安全、次回ビルドで自動再構築
Xcode/Archives リリースビルド(.xcarchive)dSYM シンボル表含む 2–30 GB ⚠️ 旧版は削除可、現行バージョンは dSYM を保持
Xcode/iOS DeviceSupport 実機接続時にダウンロードされるデバッグシンボル 1–3 GB / iOS バージョンごと ✅ 旧版は削除可、デバイス再接続で自動再ダウンロード
CoreSimulator/Profiles/Runtimes シミュレータランタイムイメージ 5–10 GB / iOS バージョンごと ⚠️ 使わないバージョンは削除可、再ダウンロード必要
CoreSimulator/Devices 作成済みシミュレータインスタンスデータ 1–15 GB ✅ unavailable 状態は安全に削除可
Caches/org.swift.swiftpm SPM パッケージキャッシュ 1–8 GB ✅ 削除可、次回 resolve で自動再構築
Caches/com.apple.dt.Xcode Xcode 内部キャッシュ(プレビュー、IB) 0.5–3 GB ✅ 削除可
核心結論:DerivedData 下のすべての内容は再構築可能なキャッシュであり、ソースコード、Provisioning Profile、App Store 提出記録とは完全に独立しています。削除後の唯一の代償は次回ビルドがフルビルドになること(中規模プロジェクトで約2–5分増加)。

DerivedData サブディレクトリ構造

各プロジェクトは DerivedData 下に独立したサブディレクトリを持ち、形式は {プロジェクト名}-{ランダムハッシュ}/ です。内部構造:

MyApp-abcdefghijklmn/
├── Build/
│   ├── Products/          # ビルド成果物(.app, .framework, .o ファイル)
│   └── Intermediates.noindex/  # 中間ファイル(.o, .d 依存グラフ)
├── Index.noindex/         # SourceKit インデックス(ジャンプ、補完)
├── Logs/                  # ビルドログ(xcodebuild -resultBundlePath もここ)
└── info.plist             # プロジェクトパス記録

Build/Intermediates.noindex が通常最大——200個の Swift ファイルを含む中規模プロジェクトでは、このディレクトリだけで簡単に 2 GB を超えます。Index.noindex を加えると、単一プロジェクトの DerivedData が 5–10 GB に達することも珍しくありません。

5ステップでディスク圧迫源を素早く特定

いきなり無差別クリーンアップしないでください。3分かけて特定すれば、闇雲に削除するより効率的です。以下のフローは 256 GB M4 Mac Mini で実測し、2分以内に Top 5 ディレクトリを特定できます。

Step 1:ディスク全体の使用状況を確認

# ディスク全体の使用率を確認
df -h /

# ルートディスクの上位10大ディレクトリを素早く特定
sudo du -sh /* 2>/dev/null | sort -rh | head -10

Step 2:Developer ディレクトリの具体的な分布を特定

du -sh ~/Library/Developer/Xcode/* 2>/dev/null | sort -rh
du -sh ~/Library/Developer/CoreSimulator/Profiles/Runtimes/* 2>/dev/null | sort -rh
du -sh ~/Library/Developer/Xcode/iOS\ DeviceSupport/* 2>/dev/null | sort -rh

実測出力例(8か月稼働の CI ノード):

91G    /Users/ci/Library/Developer/Xcode/DerivedData
28G    /Users/ci/Library/Developer/CoreSimulator
18G    /Users/ci/Library/Developer/Xcode/iOS DeviceSupport
12G    /Users/ci/Library/Developer/Xcode/Archives
 6G    /Users/ci/Library/Developer/Xcode/Caches

Step 3:DerivedData 内で最も肥大化したサブプロジェクトを特定

du -sh ~/Library/Developer/Xcode/DerivedData/* 2>/dev/null | sort -rh | head -10
実測数値:15個の履歴プロジェクトがある開発マシンでは、top 3 の DerivedData サブディレクトリはそれぞれ 18 GB、12 GB、9 GB——うち2つは1年以上開いていないプロジェクトで、30 GB を無駄に占有していました。

Step 4:シミュレータの占有と状態を確認

# すべてのシミュレータと状態を一覧
xcrun simctl list devices

# 「利用不可」(OS アップグレード後の残存)のみ表示
xcrun simctl list devices | grep -i "unavailable"

Step 5:DeviceSupport のバージョン分布を確認

ls -lh ~/Library/Developer/Xcode/iOS\ DeviceSupport/

以下のような出力は、長年蓄積されたデバイスシンボルファイルを示します:

drwxr-xr-x  3 dev  staff   96B  iOS 15.4 (19E241)
drwxr-xr-x  3 dev  staff   96B  iOS 16.1 (20B82)
drwxr-xr-x  3 dev  staff   96B  iOS 17.2 (21C62)
drwxr-xr-x  3 dev  staff   96B  iOS 18.3.2 (22D82)

iOS 15、16 のシンボル表は 2026 年にはほぼ保持価値がありません(App Store 最低バージョン要件は一般的に iOS 17 に達しています)。安心して削除できます。

ディレクトリ別対処:削除可・慎重に・不可

直接削除可能(ゼロリスク)

# 1. すべてのプロジェクトのビルドキャッシュをクリア
rm -rf ~/Library/Developer/Xcode/DerivedData/*

# 2. 利用不可シミュレータを削除
xcrun simctl delete unavailable

# 3. SPM パッケージキャッシュをクリーンアップ
rm -rf ~/Library/Caches/org.swift.swiftpm/*

# 4. Xcode 内部キャッシュをクリーンアップ
rm -rf ~/Library/Caches/com.apple.dt.Xcode/*

# 5. SwiftUI プレビューキャッシュをクリーンアップ
rm -rf ~/Library/Developer/Xcode/UserData/Previews/*

選択的削除(古いものを削除、新しいものを保持)

# 2バージョン以前のデバイスシンボルを削除(最新2つの iOS バージョンを保持)
# まず現在のバージョンを確認
ls ~/Library/Developer/Xcode/iOS\ DeviceSupport/

# 例:iOS 18.x のみ保持し、それ以前を削除
rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport/iOS\ 15*
rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport/iOS\ 16*
rm -rf ~/Library/Developer/Xcode/iOS\ DeviceSupport/iOS\ 17*

慎重に対処:Archives

  • そのバージョンが App Store から削除済み、またはアクティブユーザーがいないことを確認
  • まだユーザーがいる場合:dSYM を個別エクスポート(Organizer → Archive を右クリック → Show in Finder → .dSYM を取り出す)
  • dSYM を Firebase Crashlytics / Sentry などのクラッシュ分析プラットフォームにアップロード
  • プラットフォームが dSYM を受信したことを確認してから、対応する Archive を削除

ワンクリック緊急コマンド(ディスク逼迫時)

以下のコマンドを安全な順序で実行すると、通常 20–60 GB を素早く解放できます:

#!/bin/bash
# emergency-clean-xcode.sh
# 実行前に確認:実行中の xcodebuild プロセスがないこと
echo "=== Xcode ディスク緊急クリーンアップ ==="

echo "[1/4] DerivedData をクリーンアップ..."
du -sh ~/Library/Developer/Xcode/DerivedData 2>/dev/null
rm -rf ~/Library/Developer/Xcode/DerivedData/*
echo "✓ DerivedData をクリアしました"

echo "[2/4] 利用不可シミュレータを削除..."
xcrun simctl delete unavailable
echo "✓ 利用不可シミュレータを削除しました"

echo "[3/4] SPM と Xcode キャッシュをクリーンアップ..."
rm -rf ~/Library/Caches/org.swift.swiftpm/*
rm -rf ~/Library/Caches/com.apple.dt.Xcode/*
echo "✓ キャッシュをクリーンアップしました"

echo "[4/4] プレビューキャッシュをクリーンアップ..."
rm -rf ~/Library/Developer/Xcode/UserData/Previews/*
echo "✓ プレビューキャッシュをクリーンアップしました"

echo ""
echo "=== クリーンアップ完了、現在のディスク状態 ==="
df -h /
💡 根本的な解決策:CI ノードがローカル物理マシンの場合、ディスク管理は長期的な負担です。Macstripe はクラウド専用 M4 Mac Miniを提供し、日/週/月単位で課金、使用後にノードをリセット可能——DerivedData 蓄積問題が根本的に解消されます。料金プランを見る →

CI/CD パイプライン防塞策

ローカル開発マシンの手動クリーンアップは対応可能ですが、CI Runner は長期間無人運用されるため、体系的な防御が必要です。ここでは一般的な自前ホスト macOS Runner(GitHub Actions / GitLab CI)を例に、3つの方案を提示します。

方案 A:DerivedData パス固定 + 増分キャッシュ

DerivedData を制御可能なパスに向け、CI キャッシュ機構と組み合わせてジョブ間で再利用:

# .github/workflows/ios-build.yml 抜粋
- name: Build
  run: |
    xcodebuild \
      -project MyApp.xcodeproj \
      -scheme MyApp \
      -configuration Release \
      -derivedDataPath /tmp/derived-data \
      -resultBundlePath /tmp/result.xcresult \
      build

- name: Cache DerivedData
  uses: actions/cache@v4
  with:
    path: /tmp/derived-data
    key: derived-data-${{ runner.os }}-${{ hashFiles('**/Package.resolved') }}-${{ hashFiles('**/*.xcodeproj/project.pbxproj') }}
    restore-keys: |
      derived-data-${{ runner.os }}-
注意:キャッシュ key には Package.resolvedproject.pbxproj のハッシュを含める必要があります。そうしないと Swift Package アップグレード後に古いキャッシュがヒットし、ビルドが失敗します。

方案 B:ビルド前後に古いキャッシュを自動クリーンアップ

# ビルドステップの前:7日以上未使用の DerivedData サブディレクトリをクリーンアップ
- name: Clean stale DerivedData
  run: |
    find ~/Library/Developer/Xcode/DerivedData \
      -maxdepth 1 -mindepth 1 \
      -type d \
      -atime +7 \
      -exec rm -rf {} +
    echo "DerivedData クリーンアップ完了、現在のサイズ:"
    du -sh ~/Library/Developer/Xcode/DerivedData 2>/dev/null || echo "ディレクトリは空"

方案 C:GitLab CI ディスク容量ゲート

.gitlab-ci.yml にプリチェックジョブを追加し、ディスク不足時に fail-fast して、ビルド途中でディスク満杯によりクラッシュし無効な成果物が生成されるのを防ぎます:

# .gitlab-ci.yml
check_disk:
  stage: .pre
  script:
    - |
      AVAIL=$(df -k / | awk 'NR==2 {print $4}')
      THRESHOLD=$((10 * 1024 * 1024))  # 10 GB in KB
      if [ "$AVAIL" -lt "$THRESHOLD" ]; then
        echo "ERROR: ディスク残量が 10 GB 未満(現在: $((AVAIL/1024/1024)) GB)、先にクリーンアップしてください"
        exit 1
      fi
      echo "ディスクチェック通過、残量: $((AVAIL/1024/1024)) GB"
  tags:
    - macos-runner

3方案の比較

方案 適用シナリオ 実装コスト キャッシュ再利用率
A:固定パス + 増分キャッシュ 中〜大規模プロジェクト、PR 頻繁、ビルド時間に敏感 中(cache action の設定が必要) 高(ジョブ間で再利用)
B:定期的に古いサブディレクトリをクリーンアップ 複数プロジェクト共有ノード、ディスクは中程度に余裕 低(find コマンド1行) 中(当日再利用)
C:容量ゲート fail-fast あらゆるシナリオ、最後の防衛線として 極低(5行スクリプト) 再利用に影響なし

3方案の併用を推奨:A でビルド速度向上、B でディスク増加を制御、C を最後の防衛線として。

自動メンテナンス:定期スクリプト + 容量警告

手動クリーンアップは結局信頼できません。クリーンアップロジックをスクリプト化し、macOS launchd で定期実行すれば、ディスク問題は受動的な緊急対応から能動的な防御に変わります。

完全メンテナンススクリプト

#!/bin/bash
# xcode-maintenance.sh
# 毎週日曜午前3時の実行を推奨
# 配置パス:~/scripts/xcode-maintenance.sh

LOGFILE=~/Library/Logs/xcode-maintenance.log
THRESHOLD_GB=20  # 残量がこの値未満でディープクリーンアップをトリガー

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOGFILE"; }

log "=== Xcode 定期メンテナンス開始 ==="

# 1. クリーンアップ前のディスク状態を記録
BEFORE=$(df -h / | awk 'NR==2 {print $4}')
log "クリーンアップ前のディスク空き: $BEFORE"

# 2. 14日以上アクセスされていない DerivedData サブディレクトリを削除
log "14日以上未使用の DerivedData をクリーンアップ..."
find ~/Library/Developer/Xcode/DerivedData \
  -maxdepth 1 -mindepth 1 -type d -atime +14 \
  -exec rm -rf {} + 2>/dev/null
log "✓ DerivedData の古いエントリをクリーンアップしました"

# 3. 利用不可シミュレータを削除
log "利用不可シミュレータをクリーンアップ..."
xcrun simctl delete unavailable 2>/dev/null
log "✓ 利用不可シミュレータを削除しました"

# 4. SPM キャッシュをクリーンアップ(30日以上)
find ~/Library/Caches/org.swift.swiftpm -maxdepth 2 \
  -type f -atime +30 -delete 2>/dev/null
log "✓ 古い SPM キャッシュをクリーンアップしました"

# 5. 残量をチェックし、閾値未満ならディープクリーンアップをトリガー
AVAIL_GB=$(df -g / | awk 'NR==2 {print $4}')
if [ "$AVAIL_GB" -lt "$THRESHOLD_GB" ]; then
  log "⚠️  ディスク残量 ${AVAIL_GB}GB < ${THRESHOLD_GB}GB、ディープクリーンアップをトリガー"
  rm -rf ~/Library/Developer/Xcode/DerivedData/*
  rm -rf ~/Library/Caches/com.apple.dt.Xcode/*
  rm -rf ~/Library/Developer/Xcode/UserData/Previews/*
  log "✓ ディープクリーンアップ完了"
fi

AFTER=$(df -h / | awk 'NR==2 {print $4}')
log "クリーンアップ後のディスク空き: $AFTER"
log "=== メンテナンス完了 ==="

launchd 定期タスクとして登録

スクリプトを毎週日曜午前3時に自動実行するよう登録:

# 1. スクリプトに実行権限を付与
chmod +x ~/scripts/xcode-maintenance.sh

# 2. launchd plist を作成
cat > ~/Library/LaunchAgents/com.myteam.xcode-maintenance.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.myteam.xcode-maintenance</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>/Users/YOUR_USER/scripts/xcode-maintenance.sh</string>
  </array>
  <key>StartCalendarInterval</key>
  <dict>
    <key>Weekday</key><integer>0</integer>
    <key>Hour</key><integer>3</integer>
    <key>Minute</key><integer>0</integer>
  </dict>
  <key>StandardOutPath</key>
  <string>/tmp/xcode-maintenance-stdout.log</string>
  <key>StandardErrorPath</key>
  <string>/tmp/xcode-maintenance-stderr.log</string>
</dict>
</plist>
EOF

# 3. ロード
launchctl load ~/Library/LaunchAgents/com.myteam.xcode-maintenance.plist
echo "定期タスクを登録しました"
実測効果:あるチームが4台の自前ホスト Mac Mini CI ノードにこのスクリプトを展開後、3か月連続でディスク警告が発生しませんでした。毎週の定期クリーンアップで 3–5 GB の回収量を維持し、ノードは安定して 60 GB 以上の空き容量を保持しています。

クラウド Mac でディスク問題を根本回避

上記のすべての方案は「限られたディスク」の前提での緩和策です。チームが CI インフラのアップグレードを検討しているなら、真剣に検討すべき選択肢があります:クラウド専用 Mac Mini でローカルノードを置き換えること。

ディスク管理問題はクラウドアーキテクチャでは異なる解決パスがあります:

  • 拡張 SSD の追加:Macstripe の M4 Mac Mini はストレージ拡張に対応。より大きなディスクを購入する方が手動クリーンアップよりはるかに楽
  • 周期的なノードリセット:月単位課金のノードはサイクル終了後にクリーンなマシンを再開通でき、DerivedData はゼロから——クリーンアップスクリプト不要
  • オンデマンド拡張:リリースラッシュ期にノード数を増やしてビルド負荷を分散、低峰期に縮小——ピーク容量のために長期課金不要
  • SSH 直結デバッグ:ノードで謎のビルド問題が発生したとき、ssh runner@your-node で直接ログインして調査、物理マシンのリモート管理より便利

実例:あるモバイルチームが3台のローカル Mac Mini を Macstripe クラウドノードに置き換えた後、月あたり約8–12時間の運用時間(ディスククリーンアップ、Xcode 更新、Runner 障害調査)を節約。エンジニア時給で計算すると、運用コストだけでレンタル費用の大部分をカバーします。

Macstripe クラウド Mac:専用物理 M4 Mac Mini、世界5リージョン(シンガポール / 日本 / 韓国 / 香港 / 米国西部)、SSH + VNC デュアルアクセス、約5分で開通、長約なし日単位課金。プランと開始価格を見る →

既に GitHub Actions ワークフローがあるチームは、実測:Windows だけで iOS 開発できる?Mac はもう不要? の記事も参考に、異なるプラットフォームで iOS アプリをビルドする際の完全比較を確認してください。

FAQ

Q:DerivedData を直接削除するとソースコードやリリース記録に影響しますか?

いいえ。DerivedData にはビルド成果物、SourceKit インデックス、ビルドログのみが保存され、ソースコード、Git 記録、Provisioning Profile、App Store Connect 提出とは完全に独立しています。削除後、Xcode は次回ビルド時に完全再構築します。唯一の代償はフルビルドになることで、中規模プロジェクトで約2–5分増加します。

Q:Archives ディレクトリは自由に削除できますか?

自由には削除できません。Archives 内の .xcarchive にはdSYM シンボル表が含まれ、オンラインクラッシュログのシンボル化に使用されます。削除前に確認:① そのバージョンが App Store から削除済みでアクティブユーザーがいない;② または dSYM を Firebase Crashlytics / Sentry などにアップロード済み。直近3リリースバージョンの Archive を保持し、それ以前は dSYM エクスポート後に削除することを推奨します。

Q:CI 環境で毎回フルビルドになる場合、キャッシュを再利用できますか?

可能です。-derivedDataPath /tmp/derived-data を xcodebuild に渡し、GitHub Actions actions/cache または GitLab CI の cache: 設定と組み合わせて増分同期します。Cache key には Package.resolvedproject.pbxproj のハッシュを含め、異なる依存バージョンの相互汚染を防ぎます。Swift Package が多いプロジェクトでは、増分ビルドで40–60%の時間短縮を実測しています。

Q:ディスク容量不足で xcodebuild が直接失敗する場合、どう素早く復旧しますか?

優先順位で順に実行:① rm -rf ~/Library/Developer/Xcode/DerivedData/*(通常10–60 GB 解放);② xcrun simctl delete unavailable(5–20 GB 解放);③ 2バージョン以上古い iOS DeviceSupport エントリを削除(5–15 GB 解放)。ほとんどの場合、①だけで問題解決します。

Q:Xcode の「Product > Clean Build Folder」とコマンドラインで DerivedData を削除する違いは?

Clean Build Folder は現在開いているプロジェクトのビルド成果物のみをクリーンアップし、他プロジェクトのキャッシュ、シミュレータデータ、DeviceSupport には影響しません。コマンドライン rm -rf ~/Library/Developer/Xcode/DerivedData/*すべてのプロジェクトのキャッシュを消去します。CI ノードメンテナンスにはコマンドラインを推奨、開発マシンの日常デバッグには Clean Build Folder の方が精密です。

Q:CI Runner で DerivedData の増加が特に速い場合、どう対処しますか?

原因は通常:複数 Scheme / 複数ブランチの並行ビルドで、毎回新しい DerivedData サブディレクトリが生成されること。推奨:① -derivedDataPath で単一パスに固定;② ビルドスクリプトに find ... -atime +7 -exec rm -rf {} + を追加して7日未アクセスのサブディレクトリをクリーンアップ;③ ノードディスク容量のアップグレード、または Macstripe クラウド Mac の拡張 SSD オプションの検討。

まとめ

DerivedData によるディスク圧迫は iOS 開発者がほぼ必ず遭遇する問題ですが、体系的な手段で完全に解決でき、「謎の現象」が起きるたびに慌ててクリーンアップする必要はありません。

  • 根本原因の理解:DerivedData は純粋なキャッシュで安全に削除可能;Archives は dSYM を含むため慎重に
  • 素早い診断:du -sh ~/Library/Developer/Xcode/* | sort -rh 1コマンドで圧迫源を特定
  • 分類別対処:DerivedData は迷わず削除、DeviceSupport は古いものを削除して新しいものを保持、Archives は dSYM エクスポート後に削除
  • CI 防御:固定 -derivedDataPath + 増分キャッシュ + 容量ゲートの3層防御
  • 自動化:launchd でメンテナンススクリプトをマウント、毎週自動クリーンアップ、受動的緊急対応から能動的防御へ
  • 根本解決:クラウド Mac 方案を検討し、拡張 SSD または周期的ノードリセットでディスク不安を完全に解消

チームが CI ノードの頻繁なディスク警告やビルド途中の失敗に悩んでいるなら、まず本記事の診断スクリプトを実行してください。通常10分以内に30 GB 以上を解放できます。長期的には、CI インフラをクラウド専用 Mac Mini に移行するのがより持続可能な解決策——オンデマンドで拡張でき、ディスクメンテナンスの心配も不要です。

関連記事