Using SPM for declaring a local graph

I’ve noticed some confusion about using SPM to model graphs with local packages, so I wanted to shed some light on the topic.

While SPM can describe a project graph, we believe it’s not the best tool for the job—at least not today. SPM’s design decisions make sense in the context of package resolution, but they fall short when it comes to project management. If you want full control over your graph and the developer experience within your project, we recommend limiting SPM to its core purpose: resolving external dependencies.

Should you use SPM for local packages?

We recommend against it—unless you’re sharing that package across other packages, in which case SPM might be necessary. For everything else, Tuist’s DSL is a better choice. Local packages that aren’t shared should be declared as targets in your Tuist project graph. If your Tuist project points to a local package that isn’t being shared, it’s worth reconsidering that setup.

We understand this might feel counterintuitive. SPM is widely used to model projects, and it might seem like you’re swimming against the tide. Believe us—we wish we didn’t have to make this recommendation. If Xcode provided a better solution, we’d deprecate our own and wholeheartedly endorse theirs. However, we view the reliance on SPM as a project manager as a workaround for the limitations of Xcode’s project graph, which hasn’t evolved to meet developers’ needs.

Moreover, while SPM might work fine for smaller setups, it doesn’t scale well for larger projects. Bumble conducted research on this topic (source) and reached the same conclusion: using SPM as a project manager is problematic, at least as of November 26, 2024. Of course, things might change in the future.

The dual-graph complexity

SPM introduces a second module graph, which means you’re juggling two:

  1. A static graph codified in Xcode projects and resolved partially at build time.
  2. A dynamic graph resolved by SPM at launch or compilation time.

This dual-graph setup introduces complexity, creates slowness, and can lead to unreliability in Xcode. Features that rely on a unified graph may break, and developers often face unexpected issues. To avoid this, we recommend consolidating into a single graph by converting SPM’s graph into Xcode targets. This gives you more control over dependencies, simplifies the build process, and reduces potential points of failure. With everything statically defined, your project opens ready to compile, making it more predictable and deterministic.

Looking ahead

Ideally, Apple would iteratively improve the Xcode project graph—making it extensible, platform-agnostic, and capable of supporting dependency resolution, much like how Android builds on Gradle. But with SPM being widely adopted as a project manager and the community pushing in that direction, we’re not sure if or when that might happen.

For now, we’ll continue monitoring these developments and will update our recommendations if things improve. But as it stands today, for the sake of more stable Xcode projects and a better developer experience, we strongly suggest using SPM only for resolving external dependencies.

1 Like