Hi all,
I’m seeing a reproducible incremental build slowdown after moving to a Tuist-generated project, and I’m trying to understand whether this is expected from project shape/
settings.
Observed behavior
When I modify a single Swift file and do an incremental rebuild:
Legacy non generated .xcodeproj: The Emit Swift module build phase takes ~4s
Is this expected for a non-modularized medium-sized app with many external dependencies, even with tuist cache --external-only? Or did I mess something up in my Tuist project settings
If yes, what are the most effective knobs to reduce incremental Emit Swift module time in this setup?
The goal is of course to move to a modularized structure but that will take some time and until then the developer experience might be quite affected by this.
I’m aware that I don’t provide exact steps or project to reproduce but it’s because I did not manage to really isolate this in a sample project.
The slowdown you’re seeing is expected given your setup (non-modularized, 600 files, Firebase + ComposableArchitecture). Here’s why.
What’s happening
Tuist makes dependency resolution explicit by adding compiler flags to -OTHER_SWIFT_FLAGS:
-Xcc -fmodule-map-file=... for every C/ObjC dependency (and their transitive deps). Firebase alone pulls in dozens of sub-dependencies, each with its own module map.
-load-plugin-executable for Swift macro plugins (ComposableArchitecture uses macros heavily).
In a hand-crafted .xcodeproj, dependencies are typically resolved through framework search paths and implicit module discovery, which Xcode can optimize more aggressively. Tuist makes these explicit for correctness and reproducibility, but the trade-off is a heavier compiler invocation.
Every time the Swift compiler runs “Emit Swift module” (even incrementally), it must parse and validate every one of those flags, resolve module map paths, and load plugin executables. With a single 600-file target, every compilation carries the full set of flags. That’s the worst case.
What you can do now
Inspect your flag count. Check the "Emit Swift module" compiler invocation in the build log, or run xcodebuild -showBuildSettings | grep OTHER_SWIFT_FLAGS. If you see duplicate -fmodule-map-file entries, that’s a bug worth reporting.
Audit transitive dependencies. Firebase pulls in a huge transitive tree. Each sub-dependency with a module map adds flags. Check whether you actually need all Firebase components.
Medium-term
Modularize progressively. Even extracting a few leaf modules would help significantly, since each module only carries flags for its own dependencies rather than the full set.
The ~3.5x slowdown (4s to 14s) is plausible for a non-modularized target of this size with heavy dependencies like Firebase and ComposableArchitecture. It’s not a misconfiguration, it’s an inherent cost of explicit dependency resolution that becomes pronounced in non-modularized projects. Modularizing is the most effective long-term fix.