Set up accurate Swift code completion in VS Code with SweetPad by installing xcode-build-server, generating buildServer.json, and letting SourceKit-LSP index your Xcode project.
Understanding the moving parts makes configuration straightforward. Swift code completion in VS Code is powered by SourceKit-LSP, Apple's official language server for Swift. SourceKit-LSP provides completion, diagnostics, jump-to-definition, and symbol search, but to do so accurately for an app target it must know the exact compiler arguments used to build each file — which SDK, which include paths, which module dependencies. For a standalone Swift package this is easy because the package manifest describes the build. For an Xcode project, that build information lives inside the Xcode build system, so an adapter is needed to expose it. That adapter is xcode-build-server, which implements the Build Server Protocol and writes a buildServer.json file describing how to obtain compiler arguments. SweetPad ties these together: it helps you generate buildServer.json and ensures SourceKit-LSP is used for Swift files. When all three cooperate — SourceKit-LSP, xcode-build-server, and a valid buildServer.json — you get Xcode-quality completion inside VS Code.
SourceKit-LSP ships with the Swift toolchain that comes with Xcode, so if you have full Xcode installed and selected, SourceKit-LSP is already present on your machine. You can confirm the toolchain path with xcrun --find sourcekit-lsp. The piece you must install separately is xcode-build-server, the adapter that bridges your Xcode project to the language server. On macOS the simplest route is Homebrew: run brew install xcode-build-server, then verify it with xcode-build-server --help. SweetPad expects this tool to be available on your PATH so it can invoke it when generating configuration. If the command is not found after installing, reopen your terminal or confirm that Homebrew's binary directory is on your PATH. You do not need to install a separate SourceKit-LSP binary or a third-party Swift extension that bundles its own language server; using the SourceKit-LSP from your Xcode toolchain keeps completion consistent with the compiler that actually builds your app, which is exactly what you want for reliable, non-misleading results.
The central configuration step is producing buildServer.json at your project root. The easiest path is to let SweetPad do it: open the Command Palette, run the SweetPad command that creates the build-server configuration, and select the scheme you want indexed. Under the hood this runs xcode-build-server config against your .xcodeproj or .xcworkspace with the chosen scheme and writes buildServer.json into the project directory. If you prefer the command line, run the equivalent xcode-build-server config invocation yourself, passing your workspace or project and the scheme name. The resulting file tells SourceKit-LSP how to fetch compiler arguments for each Swift source file. Choose the scheme that builds the target you are actively editing; if you edit code across multiple targets, index the scheme whose build graph includes them. Because the file can contain local build directory paths, many teams add buildServer.json to .gitignore and have each developer generate their own, rather than committing one machine's paths into the repository.
SourceKit-LSP often relies on build artifacts and index data produced by an actual build to provide the most accurate completion, so it is good practice to build the project once before expecting full results. Run a build through SweetPad or in Xcode so the build system populates derived data and the index store. This matters especially for generated code, for module maps, and for dependencies resolved through Swift Package Manager or CocoaPods, because until those modules are built, SourceKit-LSP may not be able to resolve their symbols and you will see missing completion or spurious errors around imported frameworks. After a successful build, give SourceKit-LSP a little time to index in the background; on large projects the first indexing pass can take a while. If completion is partial immediately after generating buildServer.json, a build followed by a short wait usually fills in the gaps. Think of buildServer.json as the map and the build as the territory the map describes — you generally need both.
Once buildServer.json exists and the project has been built, open a Swift file and test completion in a few realistic spots. Type a member access on a known type and confirm the completion list appears with correct symbols. Hover over a symbol to check that documentation and type information show up, and try jump-to-definition into both your own code and an imported framework like SwiftUI or UIKit. If your own symbols complete but framework symbols do not, that points to a build or SDK path issue rather than a fundamental misconfiguration. If nothing completes at all, the language server may not have started or buildServer.json may be missing or invalid. You can inspect the SourceKit-LSP output through VS Code's output panel by selecting the relevant language-server channel, which often reveals whether it found the configuration and which files it indexed. Verifying deliberately, rather than assuming, tells you exactly which layer to fix and saves time compared with blindly regenerating configuration.
Code completion accuracy drifts when your project changes but buildServer.json does not, so treat regeneration as routine maintenance. Regenerate the file whenever you add or remove targets, switch the scheme you work in, change build settings that affect compiler flags, or restructure the project. If you use Tuist or XcodeGen to generate your Xcode project, regenerate the project and then regenerate buildServer.json, in that order, because the build-server config must reflect the current project files. Adding new Swift package dependencies is another common trigger: build the project so the new modules are compiled, then confirm completion resolves their symbols, regenerating if needed. Some teams add a small script or task that regenerates buildServer.json after project generation so it never falls out of sync. Because everything here is standard tooling, a quick regenerate-and-rebuild cycle resolves the large majority of completion problems, and knowing to do it proactively keeps the editor experience smooth instead of degrading silently as the project evolves.
On big codebases, SourceKit-LSP indexing can be the slowest and flakiest part of the experience, so a few habits keep it responsive. The first indexing pass after opening a project or switching branches is the expensive one; let it finish before judging whether completion works, and watch CPU usage settle as the index store fills. Reusing the index store that Xcode already built — rather than forcing a separate clean index — saves substantial time, which is another reason to build in Xcode or through SweetPad before relying on completion. Avoid opening several unrelated Xcode projects in one VS Code window, since the language server does best with a single, well-defined workspace root that matches your buildServer.json. If completion becomes sluggish or stale after long editing sessions or many branch switches, reload the VS Code window to restart the server from a clean state. Excluding large generated or vendored directories from the workspace can also reduce noise. None of these are exotic; they are the same practices that keep any large Swift index healthy, applied through VS Code.
Even with a well-configured SourceKit-LSP setup, there are moments where Xcode remains the better tool, and being honest about that saves frustration. SourceKit-LSP completion is excellent for Swift source, but Xcode still provides tighter integration for some scenarios: working with storyboards and XIBs, asset catalog symbol generation, certain macro-heavy or generated-code situations, and the SwiftUI preview canvas, which SweetPad does not replicate. If completion behaves oddly only in a specific generated or resource-derived context, opening the file in Xcode can clarify whether the issue is your VS Code configuration or something inherent to how that code is produced. For pure Swift logic, SwiftUI views written in code, and everyday app development, the SweetPad plus SourceKit-LSP combination is fully capable and pleasant to use. Treat Xcode as the fallback for the specialized cases rather than a sign that your VS Code setup is broken; the two coexist, and the strongest workflows use each for what it does best.
No. SourceKit-LSP ships with the Swift toolchain in full Xcode, so it is already on your machine. You only need to install xcode-build-server separately, typically via Homebrew, to bridge your Xcode project to the language server.
It tells SourceKit-LSP how to obtain the compiler arguments for each Swift file in an Xcode project, using the Build Server Protocol via xcode-build-server. Without it, SourceKit-LSP cannot accurately index an Xcode project's app target and completion is incomplete.
Often no. It can contain machine-specific build paths, so many teams gitignore it and have each developer generate their own with SweetPad or xcode-build-server config. Confirm what your file contains before deciding.
That usually means the project has not been built with the current configuration, so imported modules like SwiftUI or third-party dependencies are not resolved yet. Run a build, wait for indexing, and regenerate buildServer.json if needed.
Regenerate it whenever you add or remove targets, change schemes, adjust build settings, add package dependencies, or regenerate the project with Tuist or XcodeGen. Keeping it in sync with project changes is what keeps completion accurate.
Yes. Open VS Code's output panel and select the SourceKit-LSP channel to see whether the language server started, found buildServer.json, and indexed your files. Those logs usually reveal whether the problem is missing configuration or an unbuilt dependency.