Swift 6 language mode — find strict concurrency blockers

Finds the Swift 6 strict-concurrency blockers in your .swift files — global var, static var shared, @unchecked Sendable, DispatchQueue.main.async inside async — before you flip the language mode. Runs entirely in your browser — nothing is uploaded.

Same engine as the VS Code extension, byte for byte.

Install free

Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.

VS Code MarketplaceOpen VSX (Cursor, VSCodium)npmDocker Hub
ext install ReadyStack.swift6-concurrency-lint
npx @readystack/swift6-concurrency-lint <file>
docker run --rm -v "$PWD:/w" getreadystack/swift6-concurrency-lint /w

Team? One key for every ReadyStack linter, 5 seats, $149 once

Get the full rule table as a PDF
All 11 rules Swift 6 Concurrency Migration Lint checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.

Get the full version $29

Exports one Swift 6 migration report for the whole repository — every file ranked by blocking errors, committable and CI-readable

One payment, one licence key for this tool. The key is shown right after payment.

One hour of a contract iOS engineer, at the $100/hour rates common in the US market, costs more than this licence does once.

Buy the full version — $29
ENDEJAESPT

Find a tool

· ReadyStack

Worked example

Real numbers from this tool, line by line.

Swift 6 Concurrency Migration Lint

Eleven rules read a 47-line SessionStore.swift and returned thirteen findings, six of them build-blocking errors — six lines that compile today under Swift 5 and stop compiling the moment that target moves to Swift 6 language mode. The file is not exotic. It is the shape every iOS and macOS codebase has somewhere: a shared session store, a token cache, a completion handler, a queue used as a lock.

Here is what the six errors were. A top-level var sharedCache: [String: Data] = [:], which Swift 6 rejects because a mutable global is reachable from every isolation domain at once. A second top-level var requestCount = 0. A static var shared = SessionStore() — the singleton spelling that appears in almost every tutorial written before 2024. A nonisolated(unsafe) static var lastToken, which is the same global wearing an escape hatch. A DispatchSemaphore used to turn an async call back into a blocking one, which parks a cooperative-pool thread and can deadlock the pool. And, one line above all of it, // swift-tools-version: 5.9 — the line that decides whether the package can enter Swift 6 language mode at all.

That last one is the reason a chatbot cannot finish this job. You paste a Swift file and ask whether it is Swift 6 ready; the model answers about the file. It never sees Package.swift, so it cannot tell you that the answer is moot until the tools version moves to 6.0. The lint reads **/*.swift, and Package.swift is a .swift file.

The seven remaining findings were warnings and one note: @unchecked Sendable on the class, which silences the checker without removing the race; queue.sync { } around the token array, the Swift 5 locking pattern that the isolation checker cannot see; @escaping on a completion handler with no @Sendable, which fails at the call site as soon as it is called from another domain; Task.detached, which drops the surrounding actor isolation; DispatchQueue.main.async inside a file that already uses await; and @preconcurrency import Foundation, the shim that downgrades the module's own Sendable errors to warnings while you migrate.

Assistant-written Swift concentrates these. The public Swift corpus is mostly pre-concurrency, so the default draft is a static var shared with a serial queue and a completion handler — correct Swift 5, six errors in Swift 6. The code review that catches it is a line-by-line read of every file, which is exactly the work nobody schedules.

The rewritten version of the same file — an actor SessionStore, a Sendable struct for the token, static let shared, @MainActor on the view type, await instead of the semaphore — returns zero findings from the same eleven rules. Both files ship with the extension, so the numbers here can be reproduced.

Four rules are errors (global_var, static_var, dispatch_semaphore, tools_version_5), six are warnings, one is informational. Every finding carries a line number, the reason the compiler objects, and the replacement shape.

The free extension lints the files you open and names every blocker; that job finishes with no licence key, no watermark, no usage counter. The paid tier — every file ranked by blocking errors, committable, readable in CI. One hour of a contract iOS engineer, at the $100/hour rates common in the US market, costs more than that licence does once. The same engine also runs in a single browser page with nothing uploaded: https://getreadystack.com/tools/swift6-concurrency-lint

15 seconds — what it actually does

Questions people ask

What does Swift 6 Concurrency Migration Lint actually do?

It reads your .swift files with 11 rules and lists every line that Swift 6 language mode rejects or quietly leaves racy: top-level var, static var singletons, @unchecked Sendable, nonisolated(unsafe), DispatchSemaphore, serial-queue locking, @escaping without @Sendable, and a Package.swift still pinned to swift-tools-version 5.x. Each finding carries a line number and the replacement shape.

Who is it for?

iOS and macOS developers who have a working Swift 5 codebase and a Swift 6 migration in front of them, especially teams whose recent code was drafted with an assistant. Assistants still emit the Swift 5 singleton and completion-handler shapes by default, so those files carry the largest share of blockers when the language mode is switched on.

Why not just ask a chatbot or turn on the compiler flag?

A chatbot sees only the file you paste, so it never reads the swift-tools-version line in Package.swift that decides whether Swift 6 mode can be enabled at all. Flipping the flag gives you a wall of compiler errors in build order, not in triage order, and it says nothing about the warnings that leave a race in place.

What is free and what costs money?

Free: lint the .swift files you open, with every blocker named, its line number shown, and its fix described. That job finishes with no licence key, no watermark and no usage counter. Paid at $29 once: export one migration report covering the whole repository, every file ranked by blocking errors, in a form you can commit or read in CI.

What would this cost without the tool?

The alternative is engineer hours. One hour of a contract iOS engineer, at the $100/hour rates common in the US market, already costs more than the licence, and a manual triage of a mid-sized app means opening every file to look for globals, singletons and semaphores by eye. The lint returns the same list in one pass.

Why not just ask ChatGPT or another AI chat?

A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Swift 6 Concurrency Lint - strict concurrency migration checks the file you open against 11 rules from a rule set dated 2026-09-18, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.

Ask about this tool

One question, answered by the person who built it. Your email only if you want the answer sent.

Embed this tool on your site (free)

Paste this code into your page. It runs in your visitor’s browser and stays up to date. Nothing your visitors type is stored.

 All embeddable tools

For businesses: your name and logo instead of ours, and each visitor’s result + e-mail in your inbox (only when they tick consent) — Pro from $19/month. See Pro →