A Swift Concurrency Glossary

January 25, 2025

Updated: September 17, 2025

It would be nice if there was a single place to go to look up all the terms, keywords, and annotations related to Swift concurrency. So here it is. If you notice something I've missed, pleased o let me know. Oh and of course, I included some commentary.

Also, by no means do you need to understand everything here to use Swift Concurrency successfully.

actor

Actors are the thing that define a unit of isolation. They are easy to make, but require a fair bit of understanding and practice to use successfully.

(I have now written a whole post about how and when to use an actor.)

Actor

This is kinda like AnyObject, but only for actor types. You'll rarely need this, aside from making isolated parameters.

async

This keyword marks an "effect" on a function, allowing it to use await internally and also be itself awaited.

AsyncSequence

This is a protocol that describes a sequence who's values may only be available at some point in the future.

async let

This one gives you a way to begin some work asynchronously without needing to await immediately. Does come with some subtly, but is particularly useful for managing slow, synchronous work.

await

The other half of async. You use this to introduce a potential suspension point in the currently executing task. At these points, the actor executing code can change.

@concurrent

As of Swift 6.2, you can opt into nonisolated async functions inheriting the calling isolation. This is incredibly useful, but you now cannot use that to run functions in the background. This attribute gives you a settings-independent way to ensure a function never runs on an actor.

Continuations

Asynchronous execution is not new. But, it was very commonly done using callbacks and closures. This is a whole suite of APIs that allows you to express these concepts in terms of async functions.

Default Isolation

All declarations have a well-defined static isolation, which means a default is required. This was always nonisolated, up to Swift 6.2, where we gained the ability to change this to MainActor. This capability has introduced a formal language dialect: you cannot understand the semantics of Swift code without knowing the value of this setting.

Executor

There is a pretty large set of APIs for controlling and interacting with the underlying mechanisms an actor uses to run code. This is rarely required for day-to-day Swift development, but is there for advanced uses and performance considerations.

for-await

This gives you a way to retrieve the values in an AsyncSequence via a control structure that very closely resembles a traditional for loop.

@globalActor

This is how you make an actor type "global". A global actor's type name can be referenced in annotation form, and can be used to apply static isolation.

Global Executor

Actors run code they isolate on their executor. But, there's also an executor available that can run code not isolated to any actor. Unlike actor executors, this one is not serial and can run more than one thing simultaneously. You get code on this with async let, TaskGroup, and @concurrent.

isolated

There are four ways to define isolation statically, with this being the most powerful and complex. This is an essential tool if you need to integrate concurrency into non-Sendable types.

(There's work going on to simplify this area! I've also written something about how to use it with non-Sendable types.)

@isolated(any)

There are rare cases where you may want to inspect the static isolation was of a function that has been passed around as a variable. This annotations makes that possible. If you are thinking about this, you probably want to combine it with @_inheritActorContext.

(I've written the introduction of this attribute specifically, along with a biggest post that looks at it more closely.)

isolation

Isolation is this abstraction over ways to make things thread-safe. Actors are the things that implement that safety, perhaps via a serial queue.

(I've got two things on this. One about how you use isolation and another to help think about it.)

#isolation

If you are using an isolated parameter, you may want to use this as well. I also have found it handy for printing out what the compiler thinks the isolation is at a specific point.

(I've written about this one as well.)

@_inheritActorContext

You can use this one to match the sematics of Task, so a closure can maintain the same isolation as where it was formed. Usually goes together with @isolated(any).

(There is a proposal floating around that will formalize this one, though I do have complex feelings about it.)

@MainActor

I bet you've come across this one before. It is just how you reference the shared MainActor instance.

nonisolated

Actors provide isolation, but sometimes you want to disable that. This is a handy way to hop off an actor to run some code in the background.

nonisolated(nonsending)

This is a very powerful technique for avoiding the need for Sendable types. The attribute gives you a settings-independent way to make a function that inherits the caller's isolation. Similar to the problem addressed with @concurrent, but from the other direction.

nonisolated(unsafe)

This gives you a very targeted way to opt a declaration out of the compiler's isolation checks. It is a much less-error-prone tool than @unchecked Sendable or a preconcurrency import.

@preconcurrency

If you are consuming APIs written before Swift 6, or making APIs that need to remain compatible with Swift 5 mode, you pretty much need this one.

(I've gone into some depth about how this works.)

Region-Based Isolation

This is a code-flow analysis system that allows the compiler to prove that even if a type is not Sendable, a specific usage pattern may still always be safe. It can really only work within the scope of a single function body, but the sending keyword does allow it to be even more powerful.

(My summary of this is here.)

Sendable

This provides a way to encode the thread-safety of a type into the type system. And it has no members so how complex could it possibly be?

(I haven't even written about this directly, but I did cover the general idea here.)

SendableMetatype

Prior to Swift 6.2, all types were Sendable and this concept wasn't required. But, isolated conformances brought with it some extra complexity here that required the new protocol.

@Sendable

This is exactly the same thing as Sendable, but for function types.

sending

Sometimes Sendable/@Sendable is too difficult or just unnecessarily restrictive. The sending keyword is a way relax some constraints by encoding a strict promise about the behavior of values into your function signatures.

(And, yes, I did in fact write about it!)

Task

You gotta start somewhere, and for async functions it's usually via a Task. But this type somes with a lot of features, to support things like cancellation and accessing results.

TaskGroup

A TaskGroup gives you a way to manage and control multiple child Task instances. Useful for tackling a variety of problems, including just doing a bunch of stuff simultaneously.

TaskLocal

This is kind of like the analog of thread-local values, but for tasks. They are quite an advanced tool, but there are lots of clever/tricky things you can pull off with them.

@unchecked

Sometimes, you've already got thread-safety implemented, but it is done via a mechanism don't support Swift's compiler-based checking. Declaring a type @unchecked Sendable let's you express that situation.


Did you know that I do consulting for concurrency and Swift 6 migrations? If you think I could help, get in touch.