Swift 6 Is Stricter Than You Think — Here’s What Broke for Us
Published March 31, 2026 · Jordan Kim
Swift 6 has been positioned as a refinement release, but if you’ve started experimenting with stricter concurrency checking, you may have noticed something else: code that compiled cleanly before is suddenly throwing warnings — or failing outright.
TL;DR
- Swift 6 introduces stricter enforcement around concurrency and data isolation
- Code that previously compiled may now surface Sendable and actor-related issues
- Some warnings are now treated more seriously, especially in stricter build configurations
- Most issues are fixable, but they require a clearer mental model of how data flows across threads
The First Surprise: Warnings That Suddenly Matter
One of the most noticeable changes when moving toward Swift 6 is that previously “safe enough” patterns start triggering warnings — especially around concurrency boundaries.
class DataManager {
var cache: [String: Any] = [:]
}
In earlier versions of Swift, this kind of shared mutable state might not raise immediate concerns. Under stricter checking, though, this can surface as a potential data race risk depending on how it’s used.
Sendable Shows Up Everywhere
Sendable is one of the biggest shifts in how Swift models concurrency safety. In Swift 6, it becomes much harder to ignore.
struct User {
var name: String
var metadata: [String: Any]
}
This might look harmless, but types like Any can make it difficult for the compiler to guarantee safety across concurrency boundaries.
As stricter checks are enabled, patterns like this start requiring more explicit handling or restructuring.
Actor Isolation Is Less Forgiving
Actor isolation has always been part of Swift’s concurrency model, but Swift 6 makes violations more visible — and less forgiving.
@MainActor
class ViewModel {
var title: String = ""
}
func updateTitle(vm: ViewModel) {
vm.title = "Updated"
}
Depending on where updateTitle is called from, this may now trigger warnings or errors about crossing actor boundaries without proper isolation.
Closures and Async Code Get Scrutinized More Closely
Another area where stricter checking shows up is in closures — especially those captured in asynchronous contexts.
Task {
self.doSomething()
}
Capturing self without considering isolation or sendability can now surface more explicit warnings, depending on context.
Why This Feels More Disruptive Than Expected
The biggest surprise for many teams isn’t that Swift is getting stricter — it’s how much existing code relies on assumptions that were never fully enforced.
Patterns that felt “fine in practice” now require more explicit modeling. That can make even small migrations feel larger than expected.
What Actually Helps
The fixes are usually less about silencing warnings and more about clarifying intent:
- using value types where possible instead of shared mutable state
- being explicit about actor boundaries
- avoiding overly generic types like
Anyin shared data structures - thinking carefully about what gets captured in async contexts
In other words, the compiler is pushing developers toward patterns that were already recommended — it’s just enforcing them more consistently now.
Should You Be Worried?
For most teams, this isn’t a breaking change so much as a visibility change. The underlying issues were always there — they just weren’t always surfaced.
That said, enabling stricter checking earlier rather than later can help avoid a large batch of fixes all at once.
Final Thoughts
Swift 6 isn’t trying to make development harder — it’s trying to make correctness more explicit.
But that shift can feel abrupt, especially in codebases that grew up with looser assumptions around concurrency.
If your first experience with Swift 6 involves a wall of warnings, you’re not alone. The good news is that most of them point to real improvements — even if they don’t feel that way at first.