What should the Concurrency Settings be for a brand new project?

It’s November 2025 and I have the luxury of starting a brand new application with a brand new codebase that will be targeting macOS 15+. I’m using Xcode 26.1 and will be packaging some features into Swift Packages.

What are the correct settings so that I can enable the full pro, max, ultra Swift Concurrency experience? Here's what ChatGPT, Google and I have come up with:

Xcode 26.1

  • Approachable Concurrency: "Yes"
  • Default Actor Isolation: "nonisolated" (my personal preference)
  • Strict Concurrency Checking: "Complete"
  • Swift Language Mode: "6"
  • Swift Compiler - Upcoming Features:
    • Everything "Yes" except:
    • Default Internal Imports: "No"
    • Member Import Visibility: "No"
    • Require Existential any: "No"

Swift Package

// swift-tools-version: 6.2
... snip ...
     
swiftSettings: [
  .defaultIsolation(nil),
  .enableUpcomingFeature("DisableOutwardActorInference"),
  .enableUpcomingFeature("GlobalActorIsolatedTypesUsability"),
  .enableUpcomingFeature("InferIsolatedConformances"),
  .enableUpcomingFeature("InferSendableFromCaptures"),
  .enableUpcomingFeature("NonisolatedNonsendingByDefault"),
  .enableUpcomingFeature("StrictConcurrency"),
]

I honestly don't understand the ramifications of every one of those options, even after reading the various proposals, but they sound important. :man_shrugging:

Am I missing anything? Does anything listed above not need to be included anymore? Are the Swift Package and Xcode project using the same settings?

When I create a brand new macOS + Swift + SwiftUI project in Xcode 26.1, it uses Swift 5, Minimal Checking, Approachable Concurrency and Main Actor Isolation, so I can't really use that as a comprehensive reference for a new Swift 6 project, unfortunately.

2 Likes

If you enable Swift 6 language mode, strict ("complete") concurrency checking is enabled by default as are most of the concurrency related upcoming features.
The exceptions are InferIsolatedConformances and NonisolatedNonsendingByDefault which were released with Swift 6.2 and so won't be enabled by default until Swift 7.

If you enable "Approachable Concurrency" in Xcode, then these two upcoming features are also enabled for you.

So for your package to match your Xcode configuration, you will want to enable Swift 6 mode, and then enable these two upcoming features.
"nonisolated" default actor isolation is the default, so you don't need to enable that explicitly.

"Default Internal Imports", "Member Import Visibility" and "Require Existential any" are not concurrency related. They will likely become enabled by default in a future language mode though so for an entirely new project you can consider enabling them too so you don't need to migrate later. But leaving them disabled is entirely fine too.


As for what the older concurrency upcoming features do, I'll refer you to this series by Matt Massicotte that describes the related proposals leading up to Swift 6. And then see this post of his for Swift 6.1 changes.

InferIsolatedConformances adds the ability to for a type to conform to a protocol in a way where that conformance can only be used on a specific global actor (like MainActor). There is no reason not to want to enable that feature, it is only disabled by default because there is a small chance of a source incompatibility with existing code which can require some minor source changes.

NonisolatedNonsendingByDefault on the other hand significantly changes the semantics of existing code. But for a new project it's a good idea to enable this from the start as it will become the default in the future. In addition to the evolution proposal, the Swift documentation contains a short guide to it and how you can have Swift migrate existing code.

For both of these you should be able to find various recent articles that explain these in detail so I won't try to describe them in full here myself.
But if you have specific questions about these or any of the older upcoming features, feel free to ask!

8 Likes

So in the Package.swift file, because it's annotated with 6.2 at the top, I don't need all those enableUpcomingFeature statements? I only need to include the ones for InferIsolatedConformances and NonisolatedNonsendingByDefault?

Will it always be implied that .defaultIsolation(nil) implies nonisolated? I was looking for an explicit enum value but didn't find one. Personally, I'd rather be explicit in the Package.swift file so that anyone quickly scanning it will see this value being explicitly set.

I think you covered it, thank you.

So in the Package.swift file, because it's annotated with 6.2 at the top, I don't need all those enableUpcomingFeature statements? I only need to include the ones for InferIsolatedConformances and NonisolatedNonsendingByDefault ?

swift-tools-version specifies what minimum version of the Swift compiler & tools is required to process the package file, it is independent of the language mode used to compile targets.

The package lets you define what language modes it is compatible with using the swiftLanguageModes property. And you can override the language mode per target in the swiftSettings.

So if you used swiftLanguageModes: [.v6] in the package, all targets would compile with the Swift 6 language mode by default and you would only need to enable the upcoming features you mentioned.

Will it always be implied that .defaultIsolation(nil) implies nonisolated ? I was looking for an explicit enum value but didn't find one. Personally, I'd rather be explicit in the Package.swift file so that anyone quickly scanning it will see this value being explicitly set.

I would assume this will always be true, yes. Changing it would be source breaking and would likely involve deprecating the existing API and adding a replacement with new behavior.
As you mention, there is of course nothing wrong with setting the default to make it explicit to any readers.

But the value of swift-tools-version implies a default Swift language mode, so they aren't entirely independent.

But defining // swift-tools-version: 6.2 (and not explicitly setting a swiftLanguageMode), am I not implicitly opting in to Swift Language Mode 6 and all of the stricter concurrency flags that comes along with that?

Given Package.swift is annotated with // swift-tools-version: 6.2, is .swiftLanguageModes: [.v6] also necessary?

As a side-note: Using `swift -print-supported-features` you can check what “upcoming“ flags exist and if they are maybe already enabled by default.

2 Likes

Given Package.swift is annotated with // swift-tools-version: 6.2 , is .swiftLanguageModes: [.v6] also necessary?

Yes, swift-tools-version: 6.2 does make Swift 6 the default (and minimum) language mode so .swiftLanguageModes: [.v6] is not necessary.

Great, thanks for your help.