Spend less time waiting and more time doing the work you love!
Every second counts in mobile development. But as an iOS developer, it is easy to squander time battling merge conflicts, code signing headaches and a build system that gets more complex as your projects multiply.
But the biggest time thief of all?
Slow builds.
They hit iOS developers daily, often multiple times a day. They break your flow and hoover up valuable time that could be spent on more productive and enjoyable work. In the worst cases they can seriously delay that urgent hotfix you’re trying to push to the App Store.
We’ve all been there.
But the good news is, with the right tactics, you can win back precious build time and still keep raising the quality of your app and user experience.
In this post, I’ll show you how to:
- Improve Swift hygiene for faster compilation
- Profile, cache, and parallelize builds in Xcode CI
- Maximize speed with the right hardware
If faster iOS releases are top of your wish list, you’re in the right place.
Why build speed matters for continuous integration
Every second shaved off build time means shipping features faster to your users and staying ahead of the competition. Faster builds boost momentum, reduce merge conflicts, and free developers to focus on more meaningful and enjoyable work.
Small improvements may not seem like much, but they can really add up over time leading to significant time-savings for developers.
Compiling your app faster
Apply Swift hygiene
Swift is a powerful language with wonderful features like type inference, but it is important to understand how these language features add compile-time overhead and what you can do to help the compiler work faster.
Keep functions short and focused
Long functions with many branches force the compiler to analyze every possible path, which slows down compilation. Break big functions into smaller, single-purpose units. Smaller functions allow the compiler to compile each piece independently, enabling better parallelism.
Mark classes as final
and favor value types
Non-final
classes force the compiler to assume they might be subclassed, preventing certain optimizations. To avoid this, mark any class that isn’t intended for subclassing as final
. Then use structs or enums where possible, since value types compile faster.
Here's an example:
// Before: Class could be subclassed
class User {
func displayName() -> String { … }
}
// After: Marked final, so compiler can optimize method calls
final class User {
func displayName() -> String { … }
}
Using final
lets the compiler devirtualize calls, improving build performance.
Add explicit type annotations
Swift’s type inference is convenient, but the compiler spends extra time figuring out types—especially in complex expressions or closures. To fix this, provide explicit types for variables, constants, and closures when the inferred type isn’t obvious. Also, specify return types for functions rather than relying on inference.
Here's an example:
// Before: Compiler infers [String: Banana], but spends time doing so
let dataDictionary = someFunctionThatReturnsDictionary()
// After: Explicitly declare the type, saving inference time
let dataDictionary: [String: Banana] = someFunctionThatReturnsDictionary()]
Profile and monitor builds
Even with good Swift hygiene, large projects can still be subject to slow downs. Xcode’s Build Profiler helps you spot the biggest bottlenecks.
Use Xcode’s Build Profiler
Enable build timing summary
- In Xcode, go to Product ▶ Perform Action ▶ Build Timing Summary.
- Xcode will produce a color-coded “Build Timeline” report, showing phases like Swift compilation, linking, and resource processing.
Interpret the timeline
- A healthy build profile shows many tasks running in parallel (each colored swim lane is busy).
- Large blank gaps or a single long bar, like the one below, indicates a blocking task causing serialization.

Investigate slow tasks
- Click on a long task to see which file or process is the culprit.
- Often you’ll find a single large Swift file or a module that dominates compile time, making it a prime candidate for optimization. In the example above, from the iOS Signal app, migrating from a giant if-else block to a switch eliminated the bottleneck.
Configure CI alerts
If you don’t monitor build times, you might not notice when they creep upward. Setting up an alert can prompt you to investigate before slow builds spiral out of control.
How to set it up:
- Define an SLO (Service Level Objective), for example: “No build should exceed 10 minutes.”
- In your CI system, configure an alert to trigger if the build time surpasses that 10 minute threshold. Bitrise supports this alert functionality via its Insights feature. Other CI tools may or may not have this capability.
Tackle Swift macros and build overhead
Swift macros are a powerful language feature, but they come with a cost. If you’ve authored or consumed custom macros, you might have noticed your build or test runs slowing down, especially for release configurations.
What causes overhead?
- swift-syntax dependency
- Most Swift macros rely on the swift-syntax package, which contains roughly 225,000 lines of code.
- When you add a macro to your project, SPM (the Swift Package Manager) fetches the entire SwiftSyntax source and compiles it.
- In incremental builds—when caches and DerivedData are fresh—you might not notice much difference locally. But on a CI machine (ideally a clean virtual machine for reliability) compiling SwiftSyntax can add minutes to the CI job. When you multiply that across all the CI runs your team does each day, it soon adds up.
- Most Swift macros rely on the swift-syntax package, which contains roughly 225,000 lines of code.
Compile time comparison
- In a sample project using swift-syntax built from source, a release-mode build took 18.072 seconds.
- Using swift-syntax-frameworks, the same build completed in 2.028 seconds. That’s an 89% reduction in compile time.

Looking ahead: Swift 6.2
Apple is also cooking up a solution for this, which is currently experimental:
defaults write com.apple.dt.Xcode IDEPackageEnablePrebuilts YES.
This will be turned on by default in Swift 6.2.
Upgrade your hardware for speed
Leverage the latest Apple silicon
Apple (and all chipmakers) are on an endless march toward faster and faster machines. Simply using the latest hardware can dramatically speed up your builds thanks to improvements in CPU performance, RAM, and local storage.
Apple's M4 Pro chips, the most advanced option for Mac Minis to date, enable iOS developers to build and release apps faster and more efficiently than ever before.
The M4 Pro vs M2 Pro and M1 Max: What’s the difference?
The chart below shows how the 14-core M4 Pro, 12 core M2 Pro, and 10 core M1 Max compare in key metrics such as performance, efficiency, and memory. Keep in mind that each generation manages to increase transistor count by approximately 25%.
Ensure fast, reliable local storage
Build systems—Xcode, Bazel, etc.—use a local cache (Xcode’s DerivedData) for intermediates. Limited disk space means cache eviction, leading to more rebuilds. To avoid this, opt for machines (or VMs) with sufficient SSD storage for the project requirements. Also, ensure derived data and other caches reside on the fastest local disk (e.g., NVMe), not on network-mounted volumes.
Optimize CI caching and testing
Parallelization and caching in CI
- Enable parallel builds
Pass-parallel-testing-enabled YES
toxcodebuild
so tests run in parallel across multiple simulator instances.
Wrap up: Your iOS build speed checklist
Here’s a quick recap of the top tips to speed up your iOS builds. Put them into action today to enjoy faster builds and more time for the work you love:
Here's to faster builds, less time watching progress bars, and lots of fun along the way!
Interested in more mobile dev tips and tricks? Let's chat.