Expert tips to speed up your iOS builds

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:

  1. Define an SLO (Service Level Objective), for example: “No build should exceed 10 minutes.”
  2. 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. 

Did you know?

Top performing teams on Bitrise complete PR pipelines in 10 minutes or less.

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.

Workaround example

A community member (Simon Javora) shared a clever approach: instead of pulling in SwiftSyntax as source, wrap it in an XCFramework. Usage instructions are available on the project's Github.

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%.

M4 Pro 14 coreM2 ProM1 Max Studio
Number of perfomance cores1088
Number efficiency cores442
Maximum memory64 GB32 GB64 GB

Putting M4 Pro to the test on Bitrise!

To see the impact of the M4 Pro chips firsthand, we tested two M4 Pro configurations using the public Xcode benchmark tool with the Xcode 16.2 Bitrise stack:

  • M4 Pro X Large: 14 CPU, 54 GB
  • M4 Pro Large: 7 CPU, 27 GB

The M4 Pro X Large was able to compile a large iOS codebase with Xcode 35% faster than the M2 Pro X Large. Read more about our results here, and find out how to make the switch to M4 Pro machines if you’re already a Bitrise customer.

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 to xcodebuild 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:

Swift hygiene
  • Break large functions into smaller ones.
  • Mark classes final when inheritance isn’t needed.
  • Add explicit type annotations to reduce compilation time.
Build profiling and monitoring
  • Use Xcode’s Build Timeline to spot blocking tasks.
  • Refactor or split large Swift files that dominate compile time.
  • Define a realistic SLO (e.g., build < 5 minutes).
  • Configure your CI to send alerts when that threshold is exceeded.
Swift macros
  • Pre-build swift-syntax source.
Hardware
  • Opt for the fastest machines (maximize CPU core count).
  • Ensure at least sufficient SSD storage for project caches.
CI Caching and Parallel Testing
  • Turn on simulator clones (-parallel-testing-enabled YES).
  • Split test suites into smaller, parallelizable jobs.

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.

Get Started for free

Start building now, choose a plan later.

Sign Up

Get started for free

Start building now, choose a plan later.