Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MobileNativeFoundation/rules_xcodeproj/llms.txt

Use this file to discover all available pages before exploring further.

rules_xcodeproj supports two build modes that determine what happens when you press ⌘B (or click Run) in Xcode. The choice of build mode affects build speed, artifact hermeticity, Xcode feature support, and which parts of the toolchain are responsible for compilation. Understanding the trade-offs of each mode helps you choose the right one for your team and workflow.
Build with Bazel (BwB) is the default mode. When you trigger a build in Xcode, Xcode invokes bazel build to perform the actual compilation. Xcode’s own build system is stubbed out — it acts as an orchestrator and UI layer, but Bazel does all the work.Key characteristics:
  • Bazel produces hermetic, reproducible outputs
  • Serialized diagnostics (warnings and errors) are replayed into Xcode, so they appear inline in the editor and persist between builds
  • Fix-its and warning highlights clear correctly when the underlying code is fixed
  • SwiftUI Previews are fully supported
  • Remote caching and remote execution work transparently
  • The output layout mirrors bazel-out/, giving you artifacts that are identical to a command-line bazel build
This mode is the recommended default for teams that are on Bazel or migrating to it, because it gives you the full power of Bazel’s build graph, caching, and hermeticity while still letting you use Xcode’s IDE features.

Feature comparison

FeatureBuild with BazelBuild with Xcode
Native Xcode build graph
Hermetic Bazel outputsPartial
Inline warnings & fix-its
SwiftUI Previews
Remote cachingPartial
Code coverage✅ (with config)
Archive actionLimited
Supports new Xcode features immediatelyDepends on ruleset
Identical to bazel build outputPartial

Switching between modes

The two build modes configure the generated project in different ways. If you switch modes on a project that has already built something, the artifacts in Xcode’s Derived Data may cause warnings or errors on subsequent builds. rules_xcodeproj therefore recommends declaring a separate xcodeproj target for each build mode rather than regenerating the same target with a different mode setting.
The recommended approach for teams that need both modes is to declare dedicated generation targets in a BUILD file:
BUILD
load("@rules_xcodeproj//xcodeproj:top_level_target.bzl", "top_level_target")
load("@rules_xcodeproj//xcodeproj:xcodeproj.bzl", "xcodeproj")

# Default: Build with Bazel
xcodeproj(
    name = "xcodeproj",
    project_name = "App",
    top_level_targets = [
        top_level_target(":App", target_environments = ["device", "simulator"]),
        ":Tests",
    ],
)

# Alternative: Build with Xcode (separate target, separate generated project)
xcodeproj(
    name = "xcodeproj_bwx",
    project_name = "App",
    top_level_targets = [
        top_level_target(":App", target_environments = ["device", "simulator"]),
        ":Tests",
    ],
)
Generate either project as needed:
bazel run //:xcodeproj       # Build with Bazel project
bazel run //:xcodeproj_bwx   # Build with Xcode project

Archiving and distribution

The Archive action in Xcode is not currently supported. rules_xcodeproj’s primary goal is to support running and debugging of targets, and may make optimizations that break the generated .xcarchive that the Archive action produces.
To produce an IPA or an archive for App Store distribution, build it directly with Bazel and upload the resulting artifact:
bazel build //App:App.ipa --config=release
You can then use tools like Transporter or xcrun altool to upload the IPA to App Store Connect. This approach gives you fully hermetic, reproducible release builds.

Diagnostics in Build with Bazel mode

One of the most impactful features of Build with Bazel mode is serialized diagnostics replay. After Bazel completes a build, rules_xcodeproj replays the diagnostics (warnings and errors) that Bazel serialized during compilation back into Xcode’s issue navigator and inline editor annotations. This means:
  • Warnings from previous builds persist in the issue navigator even if you haven’t re-compiled that file
  • Warnings correctly disappear when you fix the underlying issue and rebuild
  • Fix-its work exactly as they do in a native Xcode build
This behavior is powered by Bazel writing .dia (serialized diagnostics) files during compilation, which rules_xcodeproj then feeds back to Xcode after the bazel build run completes.

Build docs developers (and LLMs) love