Skip to content

XCTestDevices: the simulator clones parallel testing leaves behind

Parallel UI tests clone simulators into a folder most developers have never opened. How to measure it, and remove the clones without touching your own simulators.

5 min read

Turn on parallel testing in an Xcode scheme and every test run clones your chosen simulator several times, one per test runner. The clones live in their own simulator set, separate from the simulators you see in Xcode, at ~/Library/Developer/XCTestDevices. They are meant to be temporary. They are not always cleaned up.

Measure it

du -sh ~/Library/Developer/XCTestDevices
xcrun simctl --set ~/Library/Developer/XCTestDevices list devices

Each clone carries the data of the simulator it was cloned from, including installed apps. A team that runs UI tests locally can find this folder larger than DerivedData.

Removing them

Quit Xcode and the Simulator app, and make sure no tests are running. Then delete every device in that set, and only that set:

xcrun simctl --set ~/Library/Developer/XCTestDevices delete all

Xcode creates fresh clones the next time parallel tests run, so this costs a slower first run and nothing else.

Why the clones stay

  • Tests stopped partway, or Xcode quit during a run.
  • Several Xcode versions in use, each with its own idea of which clones it owns.
  • CI scripts that interrupt xcodebuild on timeout.

On a build machine, add the delete command to the job's cleanup step. Our guides to the iOS Simulator and DerivedData cover the other large folders in ~/Library/Developer.

Common questions

What is the XCTestDevices folder?

It holds simulator clones that Xcode creates for parallel testing, in a simulator set separate from your normal simulators, at ~/Library/Developer/XCTestDevices.

Is it safe to delete XCTestDevices?

Yes, with Xcode and tests stopped. Use xcrun simctl --set ~/Library/Developer/XCTestDevices delete all, and keep the --set part so your own simulators are untouched.

Why does XCTestDevices keep growing?

Clones are meant to be removed after testing, but interrupted runs, several Xcode versions and CI timeouts leave them behind.

Read next