Approachable Concurrency is a term first introduced in one of Swift’s vision documents to facilitate the adoption of async/await. Swift Concurrency has been available for a while, but many developers still find it difficult to adopt. Simultaneously, new developers got introduced to concurrency way too early in their adoption process. Approachable Concurrency should be an answer to both.
To clarify right away: Approachable Concurrency is an actual thing. It’s a build setting in Xcode, not just a statement. It’s the result of a vision document, and many Swift 6.2 proposals relate to it. Let’s dive into the details.
What does ‘Approachable Concurrency’ mean?
When Swift talks about “Approachable Concurrency”, it’s really about making data-race safety feel like a natural part of your day-to-day coding instead of a wall of errors you hit the moment you enable Swift 6 mode. I think we all recognize the journey of turning on strict concurrency, reverting it right after since our project suddenly has many compiler errors.
Swift’s concurrency model is incredibly powerful, but if you’re just building an app or a command-line tool that mostly lives on the main actor, it can feel like the compiler is screaming at you about sendability, actors, and global isolation long before you actually care about parallelism.
Approachable Concurrency flips that experience around: your code can start from a single-threaded, @MainActor-by-default world, where you don’t need to drown your project in annotations just to keep it compiling. You can write the same kind of sequential code you’re used to and still benefit from the compiler’s safety guarantees, without every global, protocol conformance, or override turning into a concurrency lesson.
The key idea is progressive disclosure: Swift should only ask you to understand as much concurrency as you actually use. First, you write sequential code, then you sprinkle in async/await for APIs that suspend, and only when you intentionally introduce parallelism do you have to think about actors, sendability, and complete data-race safety.
How Approachable Concurrency changes your app’s behavior
Approachable Concurrency supports progressive disclosure by treating a lot of “normal app code” as single-threaded by default, relaxing false-positive diagnostics, and making async functions behave more like you’d intuitively expect. For example, code runs in the same isolation as the caller unless you explicitly opt out. You still get the same strong guarantees once you start leaning into concurrency for performance, but the path to get there is less about fighting the compiler and more about growing your mental model step by step.
It’s very likely that your projects will result in fewer compiler warnings & errors with Swift 6.2 and approachable concurrency turned on.
FREE 5-Day Email Course: The Swift Concurrency Playbook
A FREE 5-day email course revealing the 5 biggest mistakes iOS developers make with with async/await that lead to App Store rejections And migration projects taking months instead of days (even if you've been writing Swift for years)
Enabled by default for new projects, opt-in for existing
It’s essential to be aware that this feature is enabled by default for new projects, but you must opt in for existing ones. The latter is for a reason: it changes the behavior of existing code. I highly recommend migrating each feature manually using the migration tooling. This way, your existing code will update to new features like @concurrent, and you’ll be able to apply relevant code changes manually.
If you enable the Approachable Concurrency build Setting without manual migration, your code may suddenly behave differently. The best example is NonisolatedNonsendingByDefault, where nonisolated asynchronous methods suddenly run on the callee’s actor instead of a new global executor. A manual migration would assign methods the @concurrent annotation before enabling.
If you’re about to migrate a large project, I highly recommend checking out the migration module of my Swift Concurrency course. It not only supports your journey, but it also guides you through it. Plus, the learnings from all the other 65+ lessons will compound during the migration.
A closer look at the enabled upcoming features
To better understand what happens after enabling approachable Concurrency, it’s good to discuss each upcoming feature individually.
Disable Outward Actor Isolation Inference
- Proposal: SE-401
- Implemented since Swift 5.9
- Upcoming Feature Flag:
DisableOutwardActorInference - Always enabled in Swift 6 language mode
Removes the rule where a property wrapper with global actor isolation (like @MainActor) could automatically apply that isolation to the entire type using it. This behavior was confusing and often surprising—changing one property could unexpectedly affect other code. Starting in Swift 6, actor isolation must now be explicitly declared on the type, making isolation clearer and easier to understand.
Usability of global-actor-isolated types
- Proposal: SE-434
- Implemented since Swift 6.0
- Upcoming Feature Flag:
GlobalActorIsolatedTypesUsability - Always enabled in Swift 6 language mode
Makes global-actor-isolated types (like @MainActor structs and classes) easier to use by removing unnecessary restrictions. It lets you access Sendable properties more easily, automatically treats certain functions and closures as @Sendable, and safely allows capturing non-Sendable values in isolated closures. It also fixes inheritance issues by letting subclasses add global actor isolation, as long as they don’t become Sendable if it would be unsafe. Overall, it simplifies writing safe concurrent code.
Global-actor isolated conformances
- Proposal: SE-470
- Implemented since Swift 6.2
- Upcoming Feature Flag:
InferIsolatedConformances
Allows types isolated to a global actor (like @MainActor) to conform to protocols in a way that’s limited to their actor’s context. For example, a @MainActor class can now conform to Equatable using an isolated conformance, which works only when called from the main actor. This avoids messy workarounds like nonisolated functions and improves safety by letting the compiler enforce where conformances can be used. It also introduces checks to prevent these conformances from accidentally leaking across concurrency boundaries, keeping your code safe from data races while improving how actor-isolated types interact with protocols and generics.
Inferring Sendable for methods and key path literals
- Proposal: SE-418
- Implemented since Swift 6.0
- Upcoming Feature Flag:
InferSendableFromCaptures - Always enabled in Swift 6 language mode
Improves Swift’s concurrency usability by automatically inferring @Sendable for methods and key path literals when it’s safe. If a method belongs to a Sendable type, you no longer need to manually mark partial or unapplied references as @Sendable—the compiler will do it for you. Similarly, key paths only need to be Sendable when they’re used in concurrent contexts, avoiding confusing warnings. This feature also allows you to explicitly mark key paths as Sendable when needed. This change reduces boilerplate and surprises when writing concurrent Swift code.
nonisolated(nonsending) by Default
- Proposal: SE-461
- Implemented since Swift 6.2
- Upcoming Feature Flag:
NonisolatedNonsendingByDefault
In short: Runs nonisolated async functions on the caller’s actor by default unless the function is explicitly marked @concurrent.
Enabling Upcoming Features in Xcode
I highly recommend migrating & enabling each upcoming feature individually for existing projects. This ensures you’re not suddenly introducing unexpected behavior that causes code to run on a different thread than before. I demonstrate this in detail in my YouTube video.
While you can search for Approachable Concurrency in Xcode’s build settings, I want you to search for each of the upcoming features above. For example, we could enable nonisolated(nonsending) by Default by searching for nonisolated:

Enabling Approachable Concurrency for packages
You can also enable Approachable Concurrency inside packages. For this, you’ll have to enable the Swift 6.2 tools version:
// swift-tools-version: 6.2
And manually enable all relevant upcoming features. I’ve gone ahead and did this for you, so you only have to copy and paste:
.target(
name: "YourPackageTarget",
swiftSettings: [
.enableUpcomingFeature("DisableOutwardActorInference"),
.enableUpcomingFeature("GlobalActorIsolatedTypesUsability"),
.enableUpcomingFeature("InferIsolatedConformances"),
.enableUpcomingFeature("InferSendableFromCaptures"),
.enableUpcomingFeature("NonisolatedNonsendingByDefault")
]
)
Conclusion
Approachable Concurrency is Swift’s answer to making concurrency more approachable. I’ve personally used Swift 6.2 features to successfully migrate RocketSim‘s 20+ packages. Based on that experience, I can say it’s no better time to start migrating than today.
This article just touches the surface, there is much more to learn regarding concurrency. Before you migrate, I recommend being aware of the features that exist. You can let AI do the migration, but how would you be able to validate the outcome? My Swift Concurrency course offers 65+ lessons and 10 assessments to make you the concurrency expert.
Check out the Swift Concurrency Course
Thanks!