What is rules_xcodeproj?
rules_xcodeproj is a Bazel ruleset that automatically generates Xcode projects from your BUILD files. Its used by major companies including Slack, Spotify, Cash App, Lyft, Reddit and many others.
The tool translates your Bazel build definitions into native Xcode projects that provide full IDE functionality while still using Bazel for the actual building. This means you get Bazel's reproducible builds and caching combined with Xcode's excellent development experience.
Key Features
Full Xcode IDE Support:
- Indexing (autocomplete, syntax highlighting, jump to definition)
- Debugging with breakpoints and variable inspection
- Runtime sanitizers (Address Sanitizer, Thread Sanitizer)
- Inline compiler warnings and errors
- Test selection and execution
- SwiftUI Previews
- Embedded targets (App Clips, Extensions, Watch Apps)
Focused Projects:
One standout feature is focused projects. For large codebases, you can include only a subset of targets in Xcode while Bazel builds the rest in the background. This dramatically improves Xcode performance.
Broad Compatibility:
- Core Bazel C/C++/Objective-C rules
- rules_swift
- rules_apple
- rules_ios
- Most custom rules
Installation
The latest stable version is 3.5.1
Using Bzlmod (Modern)
Add to your MODULE.bazel:
bazel_dep(name = "rules_xcodeproj", version = "3.5.1")
Using WORKSPACE (Legacy)
Add to your WORKSPACE:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_xcodeproj",
integrity = "sha256-3Dhy+1DRa7598DXqIurE950JVwNuIm1t+d5d44lDQ5M=",
url = "https://github.com/MobileNativeFoundation/rules_xcodeproj/releases/download/3.5.1/release.tar.gz",
)
load(
"@rules_xcodeproj//xcodeproj:repositories.bzl",
"xcodeproj_rules_dependencies",
)
xcodeproj_rules_dependencies()
load("@bazel_features//:deps.bzl", "bazel_features_deps")
bazel_features_deps()
load(
"@build_bazel_rules_apple//apple:repositories.bzl",
"apple_rules_dependencies",
)
apple_rules_dependencies()
load(
"@build_bazel_rules_swift//swift:repositories.bzl",
"swift_rules_dependencies",
)
swift_rules_dependencies()
load(
"@build_bazel_rules_swift//swift:extras.bzl",
"swift_rules_extra_dependencies",
)
swift_rules_extra_dependencies()
load(
"@build_bazel_apple_support//lib:repositories.bzl",
"apple_support_dependencies",
)
apple_support_dependencies()
Basic Usage Example
Here's a complete iOS app setup in a root-level BUILD file:
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"]),
)
Generate the Project
bazel run //:xcodeproj
This creates App.xcodeproj in your workspace. Open it:
open App.xcodeproj
Understanding the Configuration
xcodeproj rule attributes:
-
name: Target name for generation command -
project_name: Name of the generated .xcodeproj file -
tags = ["manual"]: Prevents building during regular bazel commands -
top_level_targets: Main targets to include in Xcode
top_level_target function:
- Wraps targets with additional configuration
-
target_environments: Specify "device", "simulator", or both - Ensures targets build for appropriate platforms
Important Concepts
BUILD Files Are Source of Truth
Your BUILD files remain the source of truth. Xcode uses Bazel to build in the background, so changes to BUILD files require regenerating the project.
When to Regenerate
Regenerate the project when:
- Adding new targets or dependencies
- Changing build settings affecting project structure
- Modifying the dependency graph
You don't need to regenerate for:
- Editing source code
- Minor changes within existing targets
Bazel Configuration
rules_xcodeproj uses special Bazel configurations isolated from your regular builds:
-
rules_xcodeproj: Base configuration -
rules_xcodeproj_generator: Project generation -
rules_xcodeproj_indexbuild: Background indexing -
rules_xcodeproj_swiftuipreviews: SwiftUI previews
To run Bazel commands matching Xcode's environment:
bazel run //:xcodeproj -- build //path/to:target
Working with Multiple Configurations
Define Debug and Release configurations:
xcodeproj(
name = "xcodeproj",
project_name = "App",
xcode_configurations = {
"Debug": {
"//command_line_option:compilation_mode": "dbg",
},
"Release": {
"//command_line_option:compilation_mode": "opt",
},
},
top_level_targets = [
top_level_target(":App", target_environments = ["device", "simulator"]),
],
)
Troubleshooting
Xcode Version Issues
If you see "Xcode version must be specified":
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license
bazel sync --configure
Changes Not Appearing
- Determine if you need to regenerate the project
- Clean Xcode's derived data (Product → Clean Build Folder)
- Verify Bazel is rebuilding the affected targets
Why rules_xcodeproj?
Before rules_xcodeproj, tools like Tulsi existed but didn't fully satisfy modern iOS development needs. rules_xcodeproj was designed from the ground up to:
- Provide complete Xcode feature support
- Require minimal configuration
- Generate natural-feeling Xcode projects
- Support focused projects for large codebases
- Work reliably with all major Apple platform rules
The tool successfully achieves all these goals, which is why it has been adopted by so many major companies.
Comparison with Other Tools
Unlike tools that proxy Xcode's build system or require extensive configuration:
- rules_xcodeproj works directly with Xcode
- Minimal configuration required (often just the example above)
- All major Xcode features work out of the box
- Active development with regular updates
- Production-ready with strong community support
Resources
For issues or questions, check existing GitHub issues or file a new one. The community is active and responsive.
Top comments (0)