We have been running into a recurring issue causing our builds in Xcode to take significantly longer than expected. Sometimes when generating incremental builds, even ones with zero actual changes, the build can suddenly take 5-6 minutes. Almost all of this time is spent on the “planning swift module” step. In some cases, we’ve seen this issue cause the build to take longer than a clean build typically takes.
Our app has a very large number of individual modules, and the build output indicates this step can take up to 30 seconds for each one.
We originally made almost exclusive use of SPM to defines these local packages and their dependencies, but migrated to Tuist in the hopes that moving the code into Xcode projects with defined target would reduce or eliminate this issue, but we’ve been seeing it again, though I believe less often.
We are running Xcode 26 using the Swift 5 compiler mode. There is nothing in the build output that I can see when these steps are running. The build timeline can be seen below. In this specific example, a file was changed in the App target, but no code in the packages/modules were changed at all.
Replanning every module in an incremental build, but scheduling no compiles, is often a sign that inputs to the build are being modified unexpectedly. For example, a misconfigured linter could be updating the timestamp of every source file without changing the content.
If you're running Xcode 26.4 beta, you can narrow this down somewhat by:
Opening the scheme editor for the scheme you're building
Select the "Build" tab
Under "Build Debugging", enable "Task Backtraces"
Reproduce the issue in an incremental build
Open the build log in the report navigator, and filter to "Recent" and "All Messages". Expanding individual tasks in the log will show a new "Task Backtrace" below the command output describing why a particular task was re-run in that incremental build.
Yes, this has been a long standing issue, especially since Xcode 26.0, where it became extremely visible. Incremental build performance hugely regressed at the same time, so they could be related, but it's unclear. Some of the incremental regression seems macro related, as the more macros used in a file, the high a chance a trivial change rebuilds a huge number of files. Are you using macros much?
As of Xcode 26.4, Xcode's build system continues to have various issues, in no particular order.
swift-syntax still builds universally when no prebuilt is available.
Prebuilt integration is still opaque and there's no way to force the system to use the prebuilt without having it go through full set up without a cache.
Under other conditions, packages may be built universally as well. We saw this when we added a watchOS target, which means our packages get built three times, iOS arm64, iOS x86_64, and watchOS arm64.
As noted here, various "bookkeeping" tasks in the build process take much longer than you'd expect. This includes the planning states, but even sometimes checking for tool versions are preformed slowly and repeatedly.
Script phases still can't be properly ordered or set to run independently of the rest of the build process, so simple linting steps are blocking.
Asset catalog compilation is absurdly slow, and you have almost no control over the work is actually does. There's no way to provide a precompiled version.
Asset catalog compilation is also single threaded, so breaking into multiple catalogs won't help with performance. You have to move them to independent targets to actually improve performance.
To go along with all these, there isn't enough information in the build logs to take action to improve build times. Swift files are built batched, but the timing info only exists for the entire batch, so there's no way to know if a particular file takes abnormally long. There's also no easy way to visualize how long individual build stages take for batches or files.
Incremental builds take longer than builds with the Xcode 26 build cache in place, which is thoroughly absurd. A single newline can cause a rebuild of virtually our entire app.
One of the causes of the big incremental builds is that we can't really modularize our app due to the lack of control over package dependencies and how they link between shared frameworks, especially when those frameworks are shared between iOS and watchOS or other platforms.
I can't report many of these bugs because I can't include the codebase in the report, so they go no where.
@owenv Thanks for the suggestion. I’ll look into enabling that setting so that I can do further investigation.
@Jon_Shier We are making heavy use of macros, given the widespread use of them in TCA and its dependencies, which are heavily used throughout our codebase.
I’ll update here if I come up with anything specific. I wonder if there’ something causing files to get marked as touched, as was suggested, but I haven’t been able to track down a specific case for that yet.
@owenv I wasn’t able to find the “Task Backtraces” option, and didn’t see any references to it in a web search. Do you have any documentation links for that setting?
I found it in the same scheme settings for the build action in Xcode 26.4, but I don't see anything in the build logs for these backtraces or module reports.
And much of my incremental build time is spent in Emit Swift module. For our app, I added a newline to our AppDelegate file and it took 10.391s in the Planning Swift module step, then took 68.9s to emit the Swift module. As a bonus, the asset catalog was uncached in the incremental build and took 20s to rebuild (and of course rebuilt all the asset catalogs in our packages).
Assets compilation can be parallelized by splitting assets into several bundles, e.g. 6-10 assets for images / icons / illustrations..., 1 separate asset with colors, and separate assets for other resources. I've done it because assets compilation was a bottleneck at some point of compilation.
Can you please clarify what do you mean. Resources can be stored in a separate precompiled framework. It is useful for resources that rarely changed.
Has this changed recently? It wasn't true last I tried back with Xcode 15-ish. Multiple catalogs in the same target were compiled in one single threaded process. It didn't help with incremental builds either, all catalogs were reprocessed even when only a small one was changed. Otherwise yes, I mentioned you could make them technically parallel by splitting them into multiple targets.
Catalog compilation produces a car file, but there's no way to just provide that car file. You have to do what you mentioned: build a separate target that you precompile and ship as a binary. There should just be a way to automate that process. Or better yet, make the compilation actually performant and parallel.
I've noticed a significant regression in my Xcode project. The preparation phase now takes around 1 minute, while the project itself takes 45 seconds to compile on Xcode 26.3.
I didn’t encounter this issue previously, as I was mainly working with smaller SPM packages (under 10k lines of code), which compiled in just a few seconds.
Yes, separate targets compile in parallel. My point was that multiple catalogs in the same target do not. You can see that by the name of the step: "Compile asset catalogs".
So you have *.bundle in the target with an asset catalog inside it, which is copied, and that copy triggers the asset catalog build? Can't say I've heard of that before.
I originally made something like this about 7 years ago, so I don't recall every detail, but as I remember, XCode launches several asset compiler processes that compile these bundles in parallel.
When our assets began to compile 1 minute, I've decide to optimize it. This way I reduced compilation to 8 seconds, so it wasn't a bottleneck anymore.
Similar can be done for storyboard / xib files, if there are a lot of them in the project.
Feel free to ask any questions!
May be it will be good to write some article how to reproduce it step by step if someone interested.