# Pitch: SwiftPM Optimization Settings

**URL:** <https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060>\
**Category:** Pitches\
**Tags:** packagemanager\
**Created:** [October 14, 2026, 5:39pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060 "2026-10-14T17:39:21Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![owenv](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owenv/32/6137_2.png) [@owenv](https://forums.swift.org/u/owenv)\
**Post date:** [October 14, 2026, 5:39pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/1 "2026-10-14T17:39:21Z")

</div>

Hello,

The following is a short pitch to add some new manifest API for controlling optimization settings in packages:

# SwiftPM Optimization Settings

- Proposal: SE-NNNN
- Author: [Owen Voorhees](https://github.com/owenv)
- Status: **Pitch**
- Implementation: [Add an optimizationLevel manifest setting for Swift/C/C++ by owenv · Pull Request #10632 · swiftlang/swift-package-manager · GitHub](https://github.com/swiftlang/swift-package-manager/pull/10632)
- Review: (pitch)

## Motivation

Today SwiftPM defaults to optimizing code for speed in the release configuration, and disables most optimization in the debug configuration. These are sensible defaults, but they're not the best choice for every package. For example, a package may want to compile its sources with `-Osize` when compiling for a platform like watchOS. Another highly performance-sensitive package might want to enable full cross-module optimization in its release configuration to allow more of the implementation to be inlined into clients. SwiftPM should give package authors more flexibility in how these settings are configured.

## Proposed solution

Introduce three new settings in SwiftPM's manifest API:

- `.optimizationLevel(.none/.speed/.size)` can be used to set the compiler's optimization level when compiling Swift or C code. In addition to the builtin values, `.custom` can be used to specify a `-O` flag SwiftPM doesn't have builtin support for, like `-Ounchecked`.
- `.crossModuleOptimization(.disabled/.default/.full)` can be used to set the cross module optimization mode used when compiling Swift code.
- `.compilationMode(.incremental/.wholeModule)` can be used to set the compilation mode used to compile Swift code.

## Detailed Design

The full set of proposed manifest API is:

````swift
/// The compiler's optimization level.
@available(_PackageDescription, introduced: 999.0)
public struct OptimizationLevel: Sendable {
    /// Compile with no optimization. This is equivalent to passing `-Onone` to the Swift compiler or `-O0` to the C/C++ compiler.
    public static let none: OptimizationLevel = OptimizationLevel(["none"])

    /// Optimize for runtime performance. This is equivalent to passing `-O` to the Swift compiler or `-O2` to the C/C++ compiler.
    public static let speed: OptimizationLevel = OptimizationLevel(["speed"])

    /// Optimize for code size. This is equivalent to passing `-Osize` to the Swift compiler or `-Os` to the C/C++ compiler.
    public static let size: OptimizationLevel = OptimizationLevel(["size"])

    /// Manually specify an optimization level flag to use when compiling, which must begin with `-O`.
    public static func custom(_ flag: String) -> OptimizationLevel {
        OptimizationLevel(["custom", flag])
    }
}

/// Sets the optimization level used by the C compiler.
///
/// Use this setting to override the selected build configuration's default optimization level.
///
/// ```swift
/// cSettings: [
/// .optimizationLevel(.size, .when(configuration: .release)),
/// ]
/// ```
///
/// - Since: First available in PackageDescription 999.
///
/// - Parameters:
/// - level: The optimization level to use.
/// - condition: A condition that restricts the application of the build setting.
@available(_PackageDescription, introduced: 6.5)
public static func optimizationLevel(
    _ level: OptimizationLevel,
     _ condition: BuildSettingCondition? = nil
) -> CSetting

/// Sets the optimization level used by the C++ compiler.
///
/// Use this setting to override the selected build configuration's default optimization level.
///
/// ```swift
/// cxxSettings: [
/// .optimizationLevel(.size, .when(configuration: .release)),
/// ]
/// ```
///
/// - Since: First available in PackageDescription 999.
///
/// - Parameters:
/// - level: The optimization level to use.
/// - condition: A condition that restricts the application of the build setting.
@available(_PackageDescription, introduced: 6.5)
public static func optimizationLevel(
    _ level: OptimizationLevel,
    _ condition: BuildSettingCondition? = nil
) -> CXXSetting

/// Sets the optimization level used by the Swift compiler.
///
/// Use this setting to override the selected build configuration's default optimization level.
///
/// ```swift
/// swiftSettings: [
/// .optimizationLevel(.size, .when(configuration: .release)),
/// ]
/// ```
///
/// - Since: First available in PackageDescription 999.
///
/// - Parameters:
/// - level: The optimization level to use.
/// - condition: A condition that restricts the application of the build setting.
@available(_PackageDescription, introduced: 999.0)
public static func optimizationLevel(
    _ level: OptimizationLevel,
    _ condition: BuildSettingCondition? = nil
) -> SwiftSetting 

````

Notably, the `optimizationLevel` API doesn't try to represent every optimization level accepted by Swift/Clang. For example, it omits discouraged flags like Swift's `-Ounchecked` and lesser used flags like Clang's `-O1`. The `.custom` API allows specifying these options without permanently committing to them as manifest API. The specific mapping of manifest settings to compiler flags is implementation-defined and may change over time alongside the compilers.

````swift
/// The cross-module optimization mode used by the Swift compiler.
@available(_PackageDescription, introduced: 999.0)
public enum CrossModuleOptimization: Sendable {
    /// Use the compiler's default cross-module optimization behavior, which exposes some optimization opportunities to clients in release builds.
    case `default`

    /// Disable cross-module optimization. This is equivalent to passing `-disable-cmo` to Swift.
    case disabled

    /// Use the compiler's full cross-module optimization behavior, which exposes additional optimization opportunities to clients. This is equivalent to passing `-cross-module-optimization` to Swift.
    case full
}

/// Sets the cross-module optimization mode used by the Swift compiler.
///
/// Cross-module optimization allows the compiler to perform more cross-module inlining and optimization by exposing parts of this module's implementation to clients.
///
/// ```swift
/// swiftSettings: [
/// .crossModuleOptimization(.full, .when(configuration: .release)),
/// ]
/// ```
///
/// - Since: First available in PackageDescription 999.
///
/// - Parameters:
/// - mode: The cross-module optimization mode to use.
/// - condition: A condition that restricts the application of the build setting.
@available(_PackageDescription, introduced: 999.0)
public static func crossModuleOptimization(
    _ mode: CrossModuleOptimization,
    _ condition: BuildSettingCondition? = nil
) -> SwiftSetting

````

Consistent with other manifest settings, customizing a target's cross module optimization setting (and the other settings introduced in this proposal) does not impact how the target's dependencies are compiled. If a target wants to, for example, expose more of its implementation to clients in support of optimization, that target must explicitly enable full CMO.

````swift
/// The compilation mode used by the Swift compiler.
@available(_PackageDescription, introduced: 999.0)
public enum CompilationMode: Sendable {
    /// Compile the module's source files separately, in-parallel, enabling incremental builds.
    case incremental

    /// Compile all of the module's source files together, enabling whole-module optimization.
    case wholeModule
}

/// Sets the compilation mode used by the Swift compiler.
///
/// Use this setting to override the selected build configuration's default compilation mode.
///
/// ```swift
/// swiftSettings: [
/// .compilationMode(.incremental, .when(configuration: .release)),
/// ]
/// ```
///
/// - Since: First available in PackageDescription 999.
///
/// - Parameters:
/// - mode: The compilation mode to use.
/// - condition: A condition that restricts the application of the build setting.
@available(_PackageDescription, introduced: 999.0)
public static func compilationMode(
    _ mode: CompilationMode,
    _ condition: BuildSettingCondition? = nil
) -> SwiftSetting

````

Not all combinations of the new settings are valid:

| `optimizationLevel` | `compilationMode` | `crossModuleOptimization` | Reason |
| --- | --- | --- | --- |
| Any | `.incremental` | `.full` | CMO requires compiling in whole module mode, so this has no effect |
| `.none` | `.wholeModule` | `.full` | CMO requires compiling with optimizations enabled, so this has no effect |

SwiftPM will report an error in these situations.

## Security

## Impact on existing packages

None. There is no change to the build of packages which don't adopt the new manifest API.

## Future Directions

### Change Default CMO Level for Packages

In the past, enabling more aggressive CMO for the release configuration of packages has been discussed. However, this proposal is intended to be solely additive, and the new API doesn't prevent us from changing the default configurations in the future.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [October 14, 2026, 7:16pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/2 "2026-10-14T19:16:00Z")

</div>

In my mind, most of these configurations should be decided at the root package level i.e. the concrete application that builds the end product. It would be weird if packages that offer libraries start to decide the optimization level or compilation mode right?

Could you expand a bit on how you expect different kinds of packages to use those new settings?

---

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [October 14, 2026, 7:23pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/3 "2026-10-14T19:23:46Z")

</div>

> [@FranzBusch](#):
>
> In my mind, most of these configurations should be decided at the root package level i.e. the concrete application that builds the end product. It would be weird if packages that offer libraries start to decide the optimization level or compilation mode right?

In the vast majority of cases I think this is true, but I can see why some specific packages might want to express things like:

- When I'm being built with optimizations on, I prefer `-Osize` to `-O`
- I'm a performance-sensitive package and would like to build with `-O` even in non-release builds and I don't particularly care if people can't step through me as easily
- I'm a very large module that compiles very slowly with WMO enabled, so I would prefer to disable it even when WMO is used elsewhere in the build ([swift-syntax](https://github.com/swiftlang/swift-syntax/issues/1194) compiles close to 10x slower with WMO enabled, at least three years ago when I measured it)

---

<div class="post-metadata">

**Author:** ![owenv](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owenv/32/6137_2.png) [@owenv](https://forums.swift.org/u/owenv)\
**Post date:** [October 14, 2026, 7:47pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/4 "2026-10-14T19:47:05Z")

</div>

Pretty much what @allevato said, there are some cases where a library can provide a better default value for these settings. For example, a library heavily dependent on specialization for acceptable performance might want to default to full CMO in release builds, or a library might want to default to -Osize over -Os because it would otherwise produce very large binaries.

As a general rule, I think we should be more aggressive about exposing more settings to configure package builds, so long as they don't cause harm in other areas like the ability for clients to consume packages, introduce undeclared dependencies, reduce caching effectiveness, etc.

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [October 14, 2026, 8:01pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/5 "2026-10-14T20:01:02Z")

</div>

I agree with @FranzBusch; the primary way I use optimization control in Rust/Cargo is to build my own application code for debuggability, whilst optimizing all my dependencies. It would be a shame to give control of it to each individual package and not (at least) allow the root package to override it.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [October 14, 2026, 8:25pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/6 "2026-10-14T20:25:21Z")

</div>

> [@owenv](#):
>
> As a general rule, I think we should be more aggressive about exposing more settings to configure package builds, so long as they don't cause harm in other areas like the ability for clients to consume packages, introduce undeclared dependencies, reduce caching effectiveness, etc.

I very much agree with this and I think these configuration options should be exposed but we need to allow root packages to override these options for arbitrary dependencies. How would one do that with this proposal?

---

<div class="post-metadata">

**Author:** ![Honza\_Dvorsky](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/honza_dvorsky/32/29867_2.png) [@Honza\_Dvorsky](https://forums.swift.org/u/Honza_Dvorsky)\
**Post date:** [October 14, 2026, 8:28pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/7 "2026-10-14T20:28:17Z")

</div>

To echo what Franz and Keith already said, I'm also surprised by the location of these settings, as they feel quite contextual to where and for what purpose the root package is being built. Libraries have no visibility into that.

That said, it might make sense both inside each package, but to also have a way for a root target to specify these settings in a way that applies to its entire transitive dependency graph.

Then the immediate question becomes which overrides which, so I wonder if this proposal should provide some answers?

My concern: if these settings become target-level, and later we'd like the root target to override them, would that be considered a breaking change? If so, then I'm worried this proposal could lock us into a design that prevents what I suspect many adopters actually need.

---

<div class="post-metadata">

**Author:** ![owenv](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/owenv/32/6137_2.png) [@owenv](https://forums.swift.org/u/owenv)\
**Post date:** [October 14, 2026, 9:31pm UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/8 "2026-10-14T21:31:06Z")

</div>

I think we'll want a way to override settings for dependencies as well, but it does need more design work and isn't what this proposal is trying to address. I don't think it would be a breaking change to add later.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [October 15, 2026, 8:21am UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/9 "2026-10-15T08:21:19Z")

</div>

I agree that we don't have to solve it all with a single proposal but can we add a future direction for overriding settings of dependencies?

---

<div class="post-metadata">

**Author:** ![ptoffy](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ptoffy/32/44481_2.png) [@ptoffy](https://forums.swift.org/u/ptoffy)\
**Post date:** [October 15, 2026, 10:38am UTC](https://forums.swift.org/t/pitch-swiftpm-optimization-settings/90060/10 "2026-10-15T10:38:09Z")

</div>

I think this would be a very useful addition. I'm in one of the situations mentioned above: I'd like a package ([ptoffy/bcrypt](https://github.com/ptoffy/bcrypt)) to always be build with optimisations, even if the end product is using debug mode. Users won't need to step through my code and there's a noticeable performance improvement (~149ms vs ~440ms to hash a cost 12 password) which in debug I simply cannot achieve.
