Overview
Writing Swift can sometimes introduce a lot of ceremony. Repeated setup, protocol requirements, and mechanical conversions are the kinds of patterns developers often call boilerplate.
Swift Macros give developers a way to generate some of that repetitive code at compile time. They were introduced around WWDC 2023, and they opened the door for new Swift and SwiftUI features that feel built into the language while still being distributed as packages.
What Are Swift Macros?
Before macros, adding new language behavior generally required a Swift Evolution proposal, discussion, implementation in the compiler, and release through a future toolchain. That process is important for the language itself, but it is not designed for every project-specific pattern.
A Swift macro lets a package author define code transformations that run during compilation. In practice, that means a macro can expand a small annotation or expression into more complete Swift code.
Macros are especially useful when a pattern is important but repetitive: generating protocol conformance helpers, creating memberwise code, reducing async completion-handler boilerplate, or adding declarations that would otherwise be easy to mistype.
Creating a Swift Macro Package
Swift macros can be created as Swift packages in Xcode. In the menu bar, choose File > New > Package.

From the package templates, choose Swift Macro.

Give the package a name, then create the project. The original example used a package named WWDC.

Xcode creates a package that includes an example #stringify macro, similar to the one demonstrated in Apple's WWDC23 session Write Swift Macros.

Exploring the Stringify Macro
Open main.swift from the client target to see how the starter macro is used.

The #stringify macro accepts a Swift expression such as a + b. It returns both the evaluated result and a string version of the expression.
let a = 17
let b = 25
let result = #stringify(a + b)
print("The value \(result.1) is \(result.0)")Macros feel a little like functions because they accept arguments. Under the hood, though, they run as compiler plugins that inspect syntax and produce expanded Swift source.
To inspect the generated code, right-click the macro use in Xcode and choose Expand Macro.

Xcode then shows the code produced by the macro expansion.

Why Use Macros?
Macros extend Swift in a controlled way. They let developers reduce repetitive boilerplate while keeping the final expanded code visible to the compiler.
A useful way to think about macros is to compare them to derived protocol conformances. For example, this model conforms to Codable without manually writing every encoding and decoding detail:
struct StarSystem: Codable {
var name, description: String
var galaxy: Galaxy
var planets: [Planet]
}Swift can synthesize the required Encodable and Decodable behavior for you. Conceptually, the compiler fills in code like this:
struct StarSystem: Codable {
var name, description: String
var galaxy: Galaxy
var planets: [Planet]
private enum CodingKeys: String, CodingKey {
case name, description, galaxy, planets
}
init(from decoder: Decoder) throws { ... }
func encode(to encoder: Encoder) throws { ... }
}That generated code is not the exact same mechanism as macros, but the motivation is similar: you write the intent once and let tooling handle the mechanical work.
Two Kinds of Swift Macros
Swift supports two broad kinds of macros: freestanding macros and attached macros.
A freestanding macro appears as an expression or declaration and starts with #.
return #stringify(a + b)An attached macro is written as an attribute on a declaration and starts with @.
@AddCompletionHandler
func sendRequest() async throws -> ResponseQuick Reference
| Macro Form | What It Does |
|---|---|
#stringify(a + b) | Uses a freestanding expression macro |
@AddCompletionHandler | Uses an attached macro on a declaration |
Expand Macro | Shows the Swift code Xcode generates from the macro |
Swift Package Manager | Distributes macro implementations as Swift packages |
Summary
- Swift macros generate Swift code during compilation.
- They help reduce boilerplate while keeping the expanded code inspectable.
- Xcode can create a starter Swift Macro package with a sample
#stringifymacro. - Freestanding macros start with
#. - Attached macros start with
@and decorate declarations. - Macros are part of the broader Swift tooling story behind modern Swift and SwiftUI improvements.
Swift macros are still an advanced topic, but the core idea is approachable: use a small piece of syntax to represent a larger pattern, then let the compiler expand it into normal Swift code.