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.

By the end of this guide you will have a fully working Xcode project generated from a Bazel workspace — complete with an iOS app target, a Swift library, and a unit test suite. The project will support both device and simulator destinations, and you’ll be able to build, run, and debug it entirely within Xcode while Bazel remains the underlying build system.
1

Prerequisites

Before you begin, make sure you have the following in place:
  • Bazel 8.0.0 or later installed (via Bazelisk is recommended).
  • An Apple-platform Bazel workspace that already uses rules_apple and rules_swift. If you’re starting from scratch, set those up first before adding rules_xcodeproj.
  • rules_xcodeproj installed in your MODULE.bazel. If you haven’t done that yet, follow the Installation guide and come back here when you’re ready.
  • Xcode installed on your Mac (any version supported by your chosen rules_xcodeproj release — see the compatibility table).
2

Define an xcodeproj Target

Add the following to your root-level BUILD file (or create one if it doesn’t exist yet). This example sets up a minimal iOS application with a Swift library and a unit test target:
BUILD
load(
    "@build_bazel_rules_apple//apple:ios.bzl",
    "ios_application",
    "ios_unit_test",
)
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
load(
    "@rules_xcodeproj//xcodeproj:defs.bzl",
    "top_level_target",
    "xcodeproj",
)

xcodeproj(
    name = "xcodeproj",
    project_name = "App",
    tags = ["manual"],
    top_level_targets = [
        top_level_target(":App", target_environments = ["device", "simulator"]),
        ":Tests",
    ],
)

ios_application(
    name = "App",
    bundle_id = "com.example.app",
    families = ["iphone", "ipad"],
    infoplists = [":Info.plist"],
    minimum_os_version = "15.0",
    visibility = ["//visibility:public"],
    deps = [":Lib"],
)

swift_library(
    name = "Lib",
    srcs = glob(["src/*.swift"]),
)

ios_unit_test(
    name = "Tests",
    bundle_id = "com.example.tests",
    minimum_os_version = "15.0",
    test_host = ":App",
    visibility = ["//visibility:public"],
    deps = [":TestLib"],
)

swift_library(
    name = "TestLib",
    srcs = glob(["test/*.swift"]),
)
A few things to note about the xcodeproj rule:
  • project_name sets the name of the generated .xcodeproj bundle.
  • top_level_targets lists the Bazel targets you want represented in Xcode. top_level_target lets you specify which environments (device, simulator) apply to each target.
  • tags = ["manual"] prevents the xcodeproj target from being built accidentally by wildcard commands like bazel build //....
Your workspace will need an Info.plist file alongside the BUILD file for the ios_application rule. You can start with a minimal plist or point to one generated by rules_apple.
3

Generate the Xcode Project

Run the following command from the root of your workspace:
bazel run //:xcodeproj
Bazel will analyze your build graph, run the rules_xcodeproj generator, and write a .xcodeproj bundle next to your BUILD file. You should see output similar to:
INFO: Analyzed target //:xcodeproj (...)
INFO: Found 1 target...
INFO: Build completed successfully, ...
Generating "App.xcodeproj"...
When the command exits successfully, App.xcodeproj will be present in your workspace root — right beside the BUILD file.
4

Open in Xcode

Open the generated project directly from the terminal:
open App.xcodeproj
Xcode will launch, import the project, and begin indexing. Select a simulator from the destination picker, press ⌘B to build, and ⌘R to run — everything works just like a hand-crafted Xcode project.
Use bazel run //:xcodeproj (not bazel build) every time you change your BUILD files, add new source targets, or update dependencies. The run command both builds the generator tool and executes it, writing the updated .xcodeproj to disk. A plain bazel build will compile the generator binary but won’t regenerate the project.

What to Do Next

Now that you have a working generated project, explore the more powerful features of rules_xcodeproj:

Focused Projects

Limit the Xcode project to just the targets you’re actively working on. Unfocused dependencies are built by Bazel in the background.

Custom Schemes

Use the xcschemes API to define exactly the build, run, test, and profile actions you need — all from your BUILD files.

Bazel Configs

Fine-tune how Bazel behaves inside Xcode by customizing the rules_xcodeproj family of .bazelrc configs for builds, index builds, and SwiftUI Previews.

Build Modes

Choose between Build with Xcode (BwX) and Build with Bazel (BwB) to match your team’s preferred workflow and caching strategy.

Build docs developers (and LLMs) love