sourcekit-bazel-bsp is a Build Server Protocol implementation that serves as a bridge between sourcekit-lsp (Swift's official Language Server Protocol) and your Bazel-based code, giving you the power to break free from the IDE side of Xcode and develop for Apple platforms like iOS in any IDE that has support for LSPs, such as Cursor, VSCode, Sublime Text, and more. If you've fully migrated away from IDEs in favor of agentic models, you can also use this to give code intelligence to agents like Claude via their LSP integration.
[!IMPORTANT] sourcekit-bazel-bsp is designed specifically for projects that use the Bazel build system under the hood. It will not work for regular Xcode projects. For Xcode, check out projects like xcode-build-server (unrelated to this project and Spotify).
https://github.com/user-attachments/assets/ca5a448d-03b1-4f8e-9de1-e403cc08953c
MODULE.bazel file:bazel_dep(name = "sourcekit_bazel_bsp", version = "0.8.3", repo_name = "sourcekit_bazel_bsp")
setup_sourcekit_bsp rule in a BUILD.bazel file of your choice. You can find the full list of arguments here. Although the exact setup differs from project to project, here's what an example setup would look like:load("@sourcekit_bazel_bsp//rules:setup_sourcekit_bsp.bzl", "setup_sourcekit_bsp")
setup_sourcekit_bsp(
name = "setup_sourcekit_bsp_example_project",
files_to_watch = [
"HelloWorld/**/*.swift",
"HelloWorld/**/*.h",
"HelloWorld/**/*.m",
"HelloWorld/**/*.mm",
"HelloWorld/**/*.c",
"HelloWorld/**/*.hpp",
"HelloWorld/**/*.cpp"
],
index_flags = [
"config=index_build",
],
index_build_batch_size = 10,
targets = [
"//HelloWorld/...",
],
)
compile_top_level = True, make sure the targets' visibility settings allow "//.bsp/skbsp_generated:__pkg__" as this is where the BSP will reference them from.bazel run {path to the rule, e.g //:setup_sourcekit_bsp}.This will result in the necessary configuration files being added to your repository. Users should then re-run the above command whenever the rule's parameters changes. We recommend adding .bsp/skbsp_generated as well as the copied binaries and .bsp/skbsp.json to your .gitignore.
The next step depends on which IDE you want to use this integration with. Follow the instructions below that match your choice.
If you don't wish to use a custom sourcekit-lsp binary, then all you need to do is install the official swift-lsp plugin for Claude. However, as we currently make use of LSP features that are not yet shipped with Xcode, you may face performance and other usability issues when using the version that is shipped with Xcode. We strongly recommend using the version provided alongside sourcekit-bazel-bsp (or compiling/providing your own) for the best experience.
To use Claude's LSP features with a custom sourcekit-lsp binary:
.lsp.json to match what's used in your project (use absolute paths if possible)..claude/settings.json (or .claude/settings.local.json):{
"enabledPlugins": {
"sourcekit-lsp-custom@sourcekit-lsp-custom-marketplace": true
},
"extraKnownMarketplaces": {
"sourcekit-lsp-custom-marketplace": {
"source": {
"source": "directory",
"path": "path-to-your-copied-claude-marketplace-folder"
}
}
}
}
Claude should now be able to launch sourcekit-lsp + sourcekit-bazel-bsp when prompted about Swift files. To test the integration, ask it about its Swift LSP capabilities.
files.exclude setting to cover all Bazel symlinks. For a complete list of recommended settings, check out the setup script from our Example project. You can see them after running the project generation.sourcekit-lsp binary by placing the provided binary from the release archive (or compiling/providing one of your own) at a place of your choice, creating a .vscode/settings.json JSON file at the root of your repository, and adding the following entry to it: "swift.sourcekit-lsp.serverPath": "(absolute path to the sourcekit-lsp binary to use)"Cmd+Shift+P -> Swift: Restart LSP Server) or reload the entire window (Cmd+Shift+P -> Reload Window) if you don't see the previous option. The BSP will then automatically bootstrap itself, with several progress indicators showing at the bottom of the IDE. It may take a while for the indexing features to kick in the first time you use it due to the lack of cache, but subsequent runs should be much faster.While a complete indexing run can take a very long time on large projects, keep in mind that you don't need one. As long as the individual target you're working with is indexed (which happens automatically as you start working on it, as the LSP prioritizes targets you're actively modifying), all of the usual indexing features will work as you'd expect. Make sure to also check the best practices below to further optimize the BSP's performance.
If you experience any trouble trying to get it to work, check out the Example/ folder for a test project with a pre-configured Bazel and .bsp/ folder setup. The Troubleshooting section below also contains instructions on how to make sure the integration is working and debug sourcekit-bazel-bsp.
The setup instructions for other IDEs (and by extension, Claude Code) will depend on how the IDE integrates with LSPs. You should then search for instructions on how to install sourcekit-lsp on your IDE of choice and enable background indexing. We also recommend finding a way to override the sourcekit-lsp binary itself for the same reasons described in the Cursor / VSCode instructions.
Although the main focus of this project is specifically Cursor / VSCode, we are very interested in knowing what your experience was integrating it with other IDEs. If you've found concrete setup steps for a particular IDE, you are welcome to open a PR including it in this README file.
//..., try to import only a small group of test targets that you think will be required to perform the task. This will greatly increase the performance of the IDE.When building a specific library for indexing, the BSP needs to compile it with the correct platform configuration (iOS, tvOS, etc.) to ensure correctness and proper cache sharing with regular full app builds. The BSP achieves this by using an aspect to build libraries through their parent top-level target:
bazel build //.bsp/skbsp_generated:wrapper_App_MyApp --output_groups=aspect_path_to_MyLibrary
If this is undesired and/or causes issues with your particular setup, you can pass the --compile-top-level flag to make the BSP directly compile the target's entire parent instead of using the aspect approach. This can be useful for projects that define fine-grained *_build_test targets and providing them as top-level targets for the BSP, as those don't require such workarounds and thus enables maximum predictability and cacheability.
setup_sourcekit_bsp(
# ...
compile_top_level = True,
)
The integration will generally display errors on the IDE if something went wrong, but if you see nothing, try the following:
Swift option on on the Output tab of the IDE. This should say something like "Activating Swift for...". After a while, the output will update to state that the extension activated successfully ("Extension activation completed"). You should also see an entry that says (found 1 packages) and another one saying Added package folder (your_workspace_folder). These indicate that the Swift extension has correctly recognized the workspace as a Swift project.SourceKit Language Server will show up, with progress indicators popping up at the bottom of the IDE (e.g. "sourcekit-bazel-bsp: Initializing...") shortly after. This means the integration is working correctly.After a while, indexing logs will show up on a separate SourceKit-LSP: Indexing tab. These are particularly useful for uncovering issues with either your setup or the BSP itself as they display all individual compilations triggered by sourcekit-lsp.
sourcekit-bazel-bsp uses Apple's OSLog infrastructure under the hood. To see the tool's logs, run log stream --process sourcekit-bazel-bsp --debug on a terminal session. (Alternatively, if you're using our Cursor / VSCode companion extension, you can see these logs directly from the special SourceKit Bazel BSP (Server) output tab.)
Some logs may be redacted. To enable extended logging and expose those logs, install the configuration profile at as described here You will then able to see the redacted logs.
If you wish for the logs to become redacted again, you can remove the configuration profile as described here.
Since sourcekit-bazel-bsp is initialized from within sourcekit-lsp, debugging it requires you to start a lldb session in advance. You can do it with the following command: lldb --attach-name sourcekit-bazel-bsp --wait-for
Once the lldb session is initialized, triggering the initialization of the Swift extension on your IDE of choice (e.g. opening a Swift file in VSCode) should eventually cause lldb to start a debugging session.
iOS Development (and more) in alternative IDEs like Cursor / VSCode, for Bazel projects
@spotify/sourcekit-bazel-bsp0.8.3 +1.2mo2026-04-21 | |
0.8.2 +2d2026-03-15 | |
0.8.1 +3d2026-03-13 | |
0.8.0 +22d2026-03-10 | |
0.7.1 +6d2026-02-15 | |
0.7.0 +7d2026-02-08 | |
0.6.0 +4d2026-01-31 | |
0.5.3 +13d2026-01-27 | |
0.5.2 +2d2026-01-14 | |
0.5.1 +15d2026-01-11 | |
0.5.0 +8d2025-12-27 | |
0.4.2 +4d2025-12-18 | |
0.4.1 +5d2025-12-14 | |
0.4.0 +1.0mo2025-12-08 | |
0.3.0 +23d2025-11-06 | |
0.2.02025-10-14 |