Package Traits in Xcode
March 27, 2026
Did you know that we got a little present in the Xcode 26.4 release? As of that version, Xcode now supports package traits. I was so excited about this when I discovered it, I immediately had to give it a try to see how it works.
I've only done some some basic experimenting, but I think it's great.
Quick Summary
SwiftPM introduced trait support in 6.1. Traits give a package a way to expose configurable options to its users. A package can define traits it supports. And then, it can conditionalize compilation and configuration based on them.
They are very flexible and really powerful!
An Example
Suppose you've made a package. It's had actual users! But you discover that a small number of those users are feeding in a very large amount of data. It's making things slow.
A solution could be a fancy data structure from swift-collections. So you add in the dependency, wire things up, and you are done. Except, now all the users, even those that are not benefiting from these fancy data structures also require swift-collections.
Traits can help here! You can define a FancyStructures trait which is off by default. Only the small number of users that actually need it can flip on.
#if FancyStructures
import Collections
// this code will only be compiled if the
// package user enables the "FancyStructures" trait.
#endif
The trait defines a condition you can use with #if within your package sources. And don't miss that import statement! A trait can conditionalize its own dependencies using this systems.
.target(
name: "MyPackage",
dependencies: [
.product(
name: "Collections",
package: "swift-collections",
condition: .when(traits: ["FancyStructures"])
),
],
),
By default, end users of this package will not even notice that you use swift-collections, because Xcode only pulls it in if that trait is enabled. I used a real feature as an example, but this could totally work for test-only dependencies too.
Managing Transitive Packages
I think this is a really wonderful way to give package users more control. They can decide what goes into their projects without you, the package author, sacrificing functionality. I've wanted to do this many times in the past. In fact, I have made this a core part of my own package design, via other mechanisms. But I'm pretty excited to have a new tool to use.
I think this is so important because a big reason people shy away from using packages is transitive dependencies. Just look at how often packages are advertised as "dependency-free".
Traits now give package authors an easy way to expose useful, optional functionality without also requiring other packages get pulled in.
This is Going To Be Popular
I plan on using this. And I predict that a lot of other package authors will too. Optional dependencies have been on my wishlist for as long as Swift has had a package manager. And you can also, of course, use it for other forms of configuration unrelated to transitive dependencies.
Now, more configuration also means more complexity for your users too. Be careful not to go overboard here. But I think this is going to end up being a pretty popular feature.
I do have other wishes though. It would be cool if I could conditionalize a dependency on it being added to the project for other reasons. I don't want to be the one to require it, but if it happens to already be here, I'd like to use it! Traits get close, but it isn't quite the same.
Anyways, I don't want to take away from this. I haven't used the system extensively, so there might be sharp edges. But I still think this one is worth celebrating.