Migrating to Strict Concurrency
Adopt Swift 6 concurrency checking incrementally.
Migrating to Strict Concurrency is a free Swift Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is Strict Concurrency?
Strict concurrency checking makes the compiler diagnose every potential data race at compile time.
In Swift 6 language mode it is on by default; in Swift 5 mode you opt in incrementally.
The Three Checking Levels
The -strict-concurrency flag has three levels: minimal (default in Swift 5), targeted (checks code already using concurrency), and complete (full Swift 6 style checking).
// Build settings example
// SWIFT_STRICT_CONCURRENCY = completeIncremental Adoption
The recommended path is to climb the levels gradually: start at targeted, fix the warnings, then move to complete before flipping the language mode to 6.
This keeps the migration manageable on large code bases.
// Step 1: targeted
// Step 2: complete (warnings)
// Step 3: Swift 6 mode (errors)Per-Module Migration
Strict concurrency is set per target. You can migrate one module at a time, leaving others on Swift 5 mode until they are ready.
// Package.swift target
// swiftSettings: [.enableExperimentalFeature("StrictConcurrency")]Common Warning: Non-Sendable Capture
The most frequent diagnostic is capturing a non-Sendable value in a Task or sending it across an actor boundary.
Fix by making the type Sendable or copying out only Sendable data.
final class Model { var name = "" }
func start(_ m: Model) {
// Warning: non-Sendable Model captured by Task
// Task { print(m.name) }
}Fixing with Value Types
Often the cleanest fix is to model data as an immutable value type, which is Sendable automatically.
struct Model: Sendable { let name: String }
func start(_ m: Model) {
Task { print(m.name) } // safe now
}Fixing with @MainActor
UI types frequently warn because they are touched from background tasks. Annotating the type @MainActor pins it to the main thread and resolves the warnings.
@MainActor
final class ViewModel {
var items: [String] = []
func reload() async {
let fetched = await load()
items = fetched
}
}
func load() async -> [String] { [] }Sendable Conformance for Existing Types
For types you control that are already thread-safe, add explicit Sendable or @unchecked Sendable conformance to silence warnings honestly.
import Foundation
final class Counter: @unchecked Sendable {
private let lock = NSLock()
private var n = 0
}Preconcurrency Imports
When a dependency has not yet annotated its API, @preconcurrency import relaxes checking for that module, downgrading errors to warnings until it is updated.
@preconcurrency import SomeLegacyFrameworkMarking Symbols @preconcurrency
You can also mark individual declarations @preconcurrency so callers from older code do not get errors when you add Sendable requirements.
@preconcurrency
func handle(_ value: Sendable) { }Verifying the Migration
When complete checking produces zero warnings, flip the target to Swift 6 mode so the guarantees become enforced errors and cannot regress.
// Package.swift
// .target(name: "App", swiftSettings: [.swiftLanguageMode(.v6)])Quick Check: Migration
Test your understanding of strict concurrency migration.
Recap: Migrating to Strict Concurrency
Strict concurrency checking moves data-race detection to compile time, with levels minimal, targeted, and complete. Migrate per module, fix non-Sendable captures with value types, @MainActor, or honest Sendable conformance, and use @preconcurrency to ease interop with un-migrated dependencies.
Once complete is warning-free, enable Swift 6 mode to lock in the guarantees.
Frequently asked questions
Is the “Migrating to Strict Concurrency” lesson free?
Yes — the full text of “Migrating to Strict Concurrency” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Migrating to Strict Concurrency”?
Adopt Swift 6 concurrency checking incrementally. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Migrating to Strict Concurrency” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Data Race Problem
- The Sendable Protocol
- Actor Isolation and nonisolated
- Migrating to Strict Concurrency