Do not remove Simulator from every CI node. Xcode 27’s new toolchain mode can let some UIKit interface documents compile without a downloaded Simulator runtime, but application-hosted tests, UI tests, and runtime compatibility checks still need Simulator or a physical device. Start with a dual-run test, then split lightweight build nodes from full test nodes.
This guide is for:
- Build engineers reducing macOS and Simulator dependencies from compile, lint, and artifact jobs.
- Test teams running XCTest, UI automation, and multi-version iOS validation.
- DevOps and platform owners changing remote Mac pools, caches, recovery rules, and routing.
Last updated September 8, 2026. Technical details were checked against the Xcode 27 release notes, Apple’s Xcode system requirements, and the current Xcode testing documentation. Xcode 27 and iOS 27 remain beta subjects at this point. Final release behavior must be rechecked before production migration.
[ SECTION_01 ] The decision starts with build time versus run time
The phrase “the project needs Simulator” hides several different dependencies. A build may need the iOS SDK and compiler tools without launching an iOS process. A test may need a test host, a destination, a booted simulated device, or a physical device. These are separate layers.
Apple has confirmed that Xcode 27 can use toolchain compilation for UIKit Interface Builder documents by default. The same release documentation also describes a fallback to Simulator mode. This confirmation applies to the documented UIKit document compilation path. It does not prove that every project, custom build setting, or direct ibtool invocation is independent of a runtime.
The first routing rule is therefore:
- If a job only compiles source, checks code, or prepares an artifact, test it on a lightweight node without a downloaded runtime.
- If a job launches the app, uses an application host, drives the interface, or checks iOS framework behavior, keep it on a full test node.
- If the project has a custom Interface Builder pipeline, treat it as unknown until the log and generated resources confirm the actual compiler mode.
Decision matrix for node placement
Use this matrix before changing the pool. “Eligible” means suitable for a candidate lightweight node, not automatically safe for production.
| Workload | Simulator-free candidate | Full Simulator or device node | Decision signal |
|---|---|---|---|
| Swift compilation and static checks | Yes | Not normally required | No app launch, test host, or runtime destination |
| UIKit Storyboard or XIB compilation | Often | Keep as fallback | Log confirms toolchain mode and resources match |
| Pure Swift logic tests | Sometimes | Keep a fallback path | No iOS process or platform behavior is exercised |
| Application-hosted unit tests | No | Yes | Test Host and destination launch the app |
| XCTest UI tests | No | Yes | The test must launch and control the application |
| SDK and runtime compatibility checks | No | Yes | The job evaluates behavior on an iOS environment |
| Archive preparation | Often | Depends on project steps | Signing, resources, and post-build scripts still need review |
The matrix gives a simple rule: remove the runtime from a job only when the job’s command, destination, and outputs prove that it does not need one.
The Xcode command-line tool reference is the appropriate place to verify the exact command path used by the runner. Do not infer behavior from a graphical Xcode session if CI invokes xcodebuild with different settings.
[ SECTION_02 ] First step: prove the Interface Builder boundary in the real project
Projects that contain Storyboards or XIB files deserve a separate validation pass. A successful compile is necessary, but it is not sufficient. The resulting interface resources still need to load correctly when the app runs.
Apple’s build settings reference documents the settings surface that controls compilation behavior. Review the project and target settings for IBC_COCOATOUCH_COMPILER_MODE, then compare them with the command-line overrides used by CI.
Use this sequence:
- Record the current Xcode version, SDK selection, active scheme, destination, and relevant build settings.
- Run a clean ordinary build on the existing full node.
- Run the same commit on a candidate lightweight remote Mac node.
- Compare the build log for Interface Builder compiler mode, warnings, generated resources, and fallback messages.
- Launch the resulting application on a full test node and inspect every affected Storyboard and XIB path.
- Save the trigger if the project falls back to Simulator mode.
- Restore the original setting and repeat the test after a clean checkout.
The important result is not “the build was green.” The result is a recorded explanation of why no Simulator runtime was requested and whether the generated interface resources behave identically.
Custom build settings can change the result. Direct ibtool calls in a script can bypass the expected target configuration. A build phase can also invoke a tool that the main build log does not make obvious. Search scripts, package plugins, and generated project settings before classifying the job as runtime-independent.
What to record when fallback occurs
A fallback should be treated as evidence, not as an unexplained failure. Record:
- The target and scheme that triggered it.
- The build command and destination.
- The Interface Builder file involved.
- The active compiler mode.
- Whether the fallback requested a Simulator runtime or only a compiler component.
- The generated resource difference.
- The setting or script that restored the build.
This record gives the platform team a rollback entry. It also prevents a future Xcode beta update from silently changing the node requirements.
For a broader acceptance process, maintain a documented remote build-node checklist alongside the project-specific log review. The build node should remain disposable until the interface resources pass runtime validation.
[ SECTION_03 ] Second step: classify tests by their host and destination
“Unit test” is not a sufficient workload label. A pure Swift test and an application-hosted XCTest target can have very different node requirements.
Pure logic tests
A test target that exercises deterministic Swift logic without launching an iOS application may be a candidate for a lightweight node. The team still needs to inspect the target’s SDK, destination, linked frameworks, and test product. A test that appears independent can become runtime-dependent after a package or framework change.
The acceptance signal is explicit:
- No Test Host is required.
- No iOS application process is launched.
- No iOS-only framework behavior is under test.
- The test result is produced without a Simulator destination.
- The same test product remains usable by the downstream pipeline.
Apple’s testing and result interpretation documentation explains how to inspect test execution and results. Use the result bundle, not only the process exit code, when confirming what actually ran.
Application-hosted tests
Application-hosted tests are different. They launch or attach to an application process. That process needs an execution environment. The test target may compile on a lightweight node, but execution belongs on a Simulator or physical-device node.
Check the following fields before routing:
- Test Host.
- Test target SDK.
- Scheme test action.
- Destination specification.
- Application bundle used by the test.
- Code signing and entitlements.
- Result bundle contents.
A green compile on a build node does not mean an application-hosted test can move there. The test must run where the application can launch.
Platform behavior and integration checks
Tests that inspect UIKit behavior, system permissions, URL handling, background execution, rendering, or other iOS platform behavior need a runtime validation path. The exact requirement may be Simulator, a physical device, or both. The correct choice depends on the behavior under test.
Apple’s guide for running an app on simulated or physical devices provides the execution boundary. It is not enough to compile the test bundle. The pipeline must show that the application launched on the intended destination.
[ SECTION_04 ] UI automation remains a full-node workload
XCTest UI tests are not replaced by Interface Builder toolchain compilation. UI automation must start the application and interact with its interface. That makes the runtime part of the workload even if the application itself compiled successfully on a lightweight node.
Use a Test Plan to make the destination and test configuration visible. Apple’s Test Plan organization guidance is useful when separating fast checks from broader device coverage.
For each UI test job, verify:
- The selected Test Plan.
- The target device or Simulator destination.
- The application launch record.
- The test result bundle.
- Screenshots, video, or failure attachments when enabled.
- The cleanup state after the job.
- Recovery after the node or simulated device restarts.
Parallel execution also needs operational evidence. The platform team should observe Simulator clone behavior, storage pressure, boot failures, and competing jobs. Do not publish a fixed capacity figure unless it comes from an official source or a clearly labeled NOVAKVM measurement. A beta release can change resource behavior, so a result from one successful run is not a capacity policy.
The remote Mac test environment should have a documented Simulator initialization and restart procedure. The procedure must be applied to the actual Xcode and runtime combination used by the test pool.
[ SECTION_05 ] Build-for-testing creates a useful split, not a free split
build-for-testing and test-without-building can separate compilation from execution. Apple documents this workflow in Technical Note TN2339. The split is useful when the build node and test node have different responsibilities, but it does not remove compatibility requirements.
A reliable handoff must preserve:
- The same Xcode toolchain family.
- The same SDK expectations.
- The test product and supporting bundles.
- Signing and provisioning inputs.
- Build configuration.
- Test Plan selection.
- Destination compatibility.
- Derived data or exported artifact rules.
- Result bundle collection.
The build node can prepare the test products. The test node still needs the environment that can execute them.
For teams using a self-hosted runner, configure the runner as a routing layer rather than proof that every job belongs on the same machine. Labels should distinguish build-only nodes from Simulator-capable test nodes. The labels must be backed by health checks. A node should not advertise UI-test capability merely because Xcode is installed.
Teams comparing this split with dedicated hardware can review the Mac mini development ordering options, but the comparison should include utilization, recovery, signing exposure, and the need for multiple concurrent test destinations rather than hardware price alone.
[ SECTION_06 ] Three node topologies fit different teams
Single pool: keep the current layout
Choose one full-capability pool when:
- The project mixes build, application-hosted tests, and UI tests in most pipelines.
- Operational simplicity matters more than reducing runtime storage.
- The team has not yet measured the build-only workload.
- The project still has frequent Interface Builder fallback events.
This topology costs more in node resources, but it reduces routing mistakes during the beta period. It is a reasonable temporary state.
Dual pool: separate build and test nodes
Choose two pools when:
- Pure builds and static checks are frequent.
- UI tests are slower or require isolated destinations.
- The team can preserve artifact and toolchain compatibility.
- The platform can observe both pools and route failed jobs back.
- A real project has passed repeated dual-run validation.
The build pool should be minimal and disposable. The test pool should retain initialized runtime images, device setup, test attachments, and recovery procedures. The separation should be visible in CI labels and dashboards.
Delayed migration: keep the full node until evidence improves
Delay the split when:
- The project invokes custom
ibtoolcommands. - The build log cannot explain why a runtime was requested.
- Test Host settings are inconsistent between schemes.
- Generated resources differ between nodes.
- A beta update changes the compiler or destination behavior.
- The team cannot reproduce a failed test after node restart.
A delayed migration is safer than removing Simulator and discovering the dependency during a release build.
[ SECTION_07 ] FAQ: practical answers for the four migration questions
Can an Xcode 27 project build without downloading Simulator?
Sometimes. The confirmed Xcode 27 toolchain mode applies to UIKit Interface Builder document compilation. It does not cover every build phase or every project customization. A pure build can be a candidate for a runtime-free node only after the CI log shows no Simulator request and the resulting Storyboard or XIB resources pass an application launch test.
Which CI tasks still need an iOS runtime?
Application-hosted tests, UI automation, and checks that depend on iOS platform behavior still need Simulator or a physical device. A source compile can use the iOS SDK without launching an iOS process, but SDK availability and runtime availability are different dependencies. Keep the execution job on the full test pool.
Can Interface Builder toolchain mode affect existing Storyboards?
It can change the compilation path for existing UIKit interface documents. Review IBC_COCOATOUCH_COMPILER_MODE, target-level overrides, scripts, and direct compiler calls. Compare generated resources and launch behavior. If the project falls back to Simulator mode, document the target, file, setting, and recovery action before trying to remove the runtime.
How should remote Mac build and test nodes be divided?
Put compilation, static checks, and artifact preparation on the lightweight pool when validation proves they do not launch an app or request a runtime. Put application-hosted tests, UI tests, and compatibility checks on the full pool. Exchange products with build-for-testing and test-without-building, then verify toolchain and destination compatibility.
[ SECTION_08 ] Release owners should use a two-track acceptance run
The release owner should choose a representative project. It should include the interface resources, application-hosted tests, and UI automation that the organization actually ships. A minimal sample project can hide the dependency the production project still has.
Run the same commit through two tracks:
- Existing full node.
- Candidate lightweight build node followed by the full test node.
Compare:
- Ordinary build output.
build-for-testingproducts.test-without-buildingexecution.- UI test result bundles.
- Interface resource behavior.
- Signing and archive inputs.
- Restart recovery.
- Fallback behavior after a failed job.
The App Store Connect build upload documentation can be used for the final artifact handoff check. A successful upload does not prove that UI validation ran, so keep upload evidence separate from test evidence.
Promote the lightweight node only when pure build jobs pass repeatedly, no hidden Simulator request appears, and the full test track remains reproducible. Keep an automatic route back to the full node. Do not make production routing depend on a single green beta run.
[ SECTION_09 ] Final decision for remote Mac planning
The current all-in-one setup has three concrete weaknesses: build jobs consume a full runtime-capable environment even when they only compile, UI-test failures can compete with unrelated artifact jobs, and recovery becomes harder when build caches and Simulator state share one node. A split remote Mac design addresses those weaknesses, but only after the project proves its dependency boundary.
The safer next move is to copy a real project to a reversible remote Mac node, run the pure build and complete test pipelines side by side, and retain the original route until the evidence is stable. If the team needs a temporary build pool, a release test pool, or a controlled beta environment without purchasing additional Mac hardware, NOVAKVM remote Mac access can provide a more flexible path than expanding the current mixed pool. Choose the rental period around the validation or release cycle, and keep long-running, high-utilization workloads under a separate cost review.