How to Bulk Delete Unavailable iOS Simulators via Terminal

Published by malhal on

If you work with Xcode long enough, your local development environment inevitably collects digital dust. Every major Xcode update, beta cycle, or iOS SDK transition leaves behind orphaned, “unavailable” simulator targets that clutter your disk space and muddy your tooling outputs.

Running xcrun simctl list might show dozens of ghost devices tied to older runtimes you no longer even have installed.

If you want to clear out the junk, doing it manually via the Xcode GUI or copying individual UUIDs is a tedious chore. Here is how to automate the cleanup instantly using the command line.

The One-Liner (The Quick Way)

Before writing custom shell scripts, Apple actually built a hidden native shorthand directly into simctl to handle basic housecleaning. If you just want to purge every single broken or unavailable simulator on your Mac right now, open your terminal and run:

Bash

xcrun simctl delete unavailable

This acts as a global sweep, instantly destroying any device container whose underlying runtime is missing.

The Targeted Way (Using JSON and jq)

Sometimes you need more granular control, or you are building an automated CI/CD build-agent cleanup script. Because simctl can export your entire simulator state as structured JSON using the -j flag, we can combine it with jq and xargs to pinpoint and destroy exactly what we want.

To find and destroy only the devices explicitly flagged with "isAvailable" : false, run this pipeline:

Bash

xcrun simctl list -j devices | jq -r '.devices[] | .[] | select(.isAvailable == false) | .udid' | xargs -I {} xcrun simctl delete {}

Breaking Down the Pipeline

If you are curious about how this script parses the nested data structure, here is what each segment is doing under the hood:

  • xcrun simctl list -j devicesOutputs your entire simulator directory structure as a clean JSON payload.
  • jq -r '.devices[] | .[]'Digs past the top-level dictionary keys (which are organized by runtime strings like com.apple.CoreSimulator.SimRuntime.iOS-18-0) and unpacks every single device object into a flat, scannable stream. The -r flag ensures the output prints as raw text instead of JSON-formatted strings wrapped in quotes.
  • select(.isAvailable == false)Acts as a conditional filter. It ignores your functional, booted, or available simulators and only passes objects downstream if they are broken.
  • .udidIsolates the raw identifier string (e.g., 74A2B6DC-EB50-4666-844C-AD7B635400E2).
  • xargs -I {} xcrun simctl delete {}Takes every unique UDID emitted by jq and sequentially drops it into a target-specific delete execution loop.

Tip: If your Mac complains that jq isn’t found, you can install it instantly via Homebrew using brew install jq. It is an essential Swiss Army knife for anyone doing framework engineering or managing build pipelines on macOS.

Categories: Xcode