Overview
Slow builds reduce productivity and increase iteration time. Tuist provides powerful optimization features including binary caching, selective testing, and build insights to dramatically speed up your development workflow.Understanding Build Performance
Build time consists of:- Compilation: Converting source code to object files
- Linking: Combining object files into executables
- Code signing: Signing binaries and frameworks
- Resource processing: Copying and processing assets
- Dependency resolution: Resolving external packages
Binary Caching
Tuist’s caching feature shares build artifacts remotely so your team and CI get faster builds without rebuilding unchanged code.Cache Types
Tuist offers different caching solutions:Module Cache
Cache individual modules as binaries for projects using Tuist-generated projects. Best for: Teams using Tuist for project generation Benefits:- Cache targets individually
- Share across team and CI
- Automatic cache invalidation
- Works with modularized apps
Xcode Cache
Share Xcode compilation artifacts across environments. Best for: Any Xcode project (no Tuist project generation required) Benefits:- Works with existing Xcode projects
- No project changes needed
- Share build artifacts
- Compatible with Xcode Build System
Gradle Cache
Share Gradle build cache artifacts remotely (for Android projects). Best for: Android projects using GradleSetting Up Module Cache
import ProjectDescription
let tuist = Tuist(
fullHandle: "your-org/your-project",
project: .tuist(
generationOptions: .options(
enableCaching: true
)
)
)
How Module Cache Works
-
Fingerprinting: Tuist calculates a hash for each target based on:
- Source files
- Dependencies
- Build settings
- Resources
- Cache lookup: Before building, Tuist checks if a cached binary exists for each target’s fingerprint
- Cache hit: If found, the cached binary is downloaded and used instead of compiling
- Cache miss: If not found, the target is compiled and the binary is uploaded to the cache
Cache Performance Example
Without caching:Selective Testing
Run only tests affected by your changes, not the entire test suite.How It Works
Tuist analyzes:- Changed source files
- Dependency graph
- Test coverage data
Using Selective Testing
Example Impact
Without selective testing:Static vs Dynamic Linking Optimization
Choose linking strategy based on the build type:Optimal Configuration
Debug builds: Dynamic linking- Faster incremental builds
- Faster iteration during development
- Larger app size (acceptable for debug)
- Faster app launch time
- Smaller app size
- Better runtime performance
Implementation
Use environment variables to switch linking:Tuist/ProjectDescriptionHelpers/Product+Linking.swift
Project.swift
Compilation Optimization
Whole Module Optimization
Optimize across entire modules in release builds:xcconfigs/Release.xcconfig
Incremental Builds for Debug
Fast iteration in debug builds:xcconfigs/Debug.xcconfig
Build Settings Best Practices
Dependency Optimization
Precompiled Dependencies
Use binary dependencies for large, stable packages:Tuist/Package.swift
Force Resolved Versions
On CI, avoid dependency resolution time:Package.resolved, skipping resolution.
Build Insights
Understand where build time is spent:Xcode Build Timeline
Generate build timeline reports:Tuist Insights
For projects using Tuist Server, access build insights:- Build duration trends
- Cache hit rates
- Slowest targets
- Build frequency
Modularization for Build Performance
Break large targets into smaller modules:Before: Monolithic Target
After: Modular Targets
Benefits of Modularization
- Faster incremental builds: Only changed modules rebuild
- Better caching: Cache individual modules
- Parallel compilation: Modules build in parallel
- Clearer dependencies: Explicit dependency graph
- Easier testing: Test modules independently
CI/CD Build Optimization
GitHub Actions Example
.github/workflows/build.yml
Cache Warming Strategy
Warm cache on main branch:.github/workflows/cache-warm.yml
Build Time Monitoring
Track Build Times
Add timing to your build scripts:build.sh
Set Build Time Goals
- Local incremental build: < 30s
- Local clean build: < 5m
- CI build (with cache): < 3m
- CI build (cold cache): < 10m
Troubleshooting Slow Builds
Identify Slow Targets
Use Xcode build timeline:-
Build with timing enabled:
- Find slowest files/functions in build log
Common Performance Issues
Issue: Cache Not Being Used
Symptoms: Every build compiles everything Solutions:- Verify
enableCaching: truein Tuist.swift - Check authentication:
tuist auth - Ensure deterministic build settings
- Review fingerprinting with
tuist cache --verbose
Issue: Slow Dependency Resolution
Symptoms:tuist install takes minutes
Solutions:
- Use
--force-resolved-versionson CI - Cache
Tuist/Dependenciesdirectory - Minimize number of dependencies
- Use binary dependencies for large packages
Issue: Slow Linking
Symptoms: Compilation fast, but linking slow Solutions:- Use dynamic linking in debug builds
- Reduce number of frameworks to link
- Enable incremental linking in debug
Issue: Slow Resource Processing
Symptoms: Long “Copy Resources” phase Solutions:- Optimize image assets (use asset catalogs)
- Compress large resources
- Move resources to dynamic frameworks
Best Practices Summary
Next Steps
Set Up CI/CD
Configure CI for optimal build performance
Project Structure
Learn how to structure projects for better builds
Manage Dependencies
Optimize dependency management
Migrate from Xcode
Enable caching by migrating to Tuist