Skip to content
Published on

Modern Swift 2026 — Swift 6.1 / SwiftUI 6 / SwiftData / Vapor 4 / Hummingbird 2 / swift-testing / Android Swift Deep Dive

Authors

Prologue — Eleven years after Objective-C left the building

When Chris Lattner unveiled Swift at WWDC 2014, the audience reacted more with a sigh than applause. "Objective-C was a 30-year-old burden, but a battle-tested burden. Do we really have to learn another language?" That was June 2014. Eleven years later in May 2026, the question has evaporated. Nearly all iOS, macOS, watchOS, visionOS, and tvOS code is Swift. Objective-C survives only in pockets of SDK internals and legacy code; every new project starts in Swift from day one. And now Swift is venturing beyond Apple platforms — onto Linux servers, Android, embedded MCUs, and even Windows.

This post draws the map of the Swift ecosystem as it stands in May 2026. The language (Swift 6.1, Swift 6.2 preview), UI (SwiftUI 6, SwiftData), server (Vapor 4, Hummingbird 2), tools (Tuist, Mint, SwiftPM), code quality (swift-syntax, swift-format, SwiftLint, SwiftFormat), testing (swift-testing), new frontiers (Android Swift WG, Embedded Swift, swift-foundation rewrite), and where Korean and Japanese shops actually use it (Kakao, LINE, Mercari, Cookpad, CyberAgent, pixiv). Which tool when, why strict concurrency is the real change, and whether Swift can really survive outside Apple's walls.


1. Modern Swift in 2026 — the strict concurrency era of Swift 6

One-line summary. The defining feature of Swift in 2026 is "data races caught at compile time." Swift 6.0 (September 2024) flipped strict concurrency on by default, Swift 6.1 (2025) stabilized the complete mode, and Swift 6.2 preview promises an even smoother actor migration. Where C++, Rust, and Go each solved concurrency safety their own way, Swift settled on the actor model + the Sendable protocol + the isolated keyword + region-based isolation.

Coordinates of Swift in 2026.

AreaStatus (2026.05)Representative tool
LanguageSwift 6.1 stableswift.org / Xcode 16
Language (preview)Swift 6.2 in Xcode 17 betaswift.org
UI framework (Apple)SwiftUI 6 (iOS 18 / macOS 15)Apple SDK
Data (Apple)SwiftData GAApple SDK
Server (de facto standard)Vapor 4vapor.codes
Server (Apple SSWG-backed)Hummingbird 2hummingbird.codes
Package managerswift-package-managerswift.org
Project generationTuist 4tuist.io
CLI tool installationMintgithub.com/yonaskolb/Mint
Macros / ASTswift-syntaxgithub.com/swiftlang/swift-syntax
Formatter (Apple official)swift-formatgithub.com/swiftlang/swift-format
Formatter (community)SwiftFormatgithub.com/nicklockwood/SwiftFormat
LinterSwiftLintgithub.com/realm/SwiftLint
Testing (new)swift-testing (Swift 6.0+)swift.org
Testing (legacy)XCTestApple SDK
AndroidAndroid Swift WG (2024.11)swift.org/android-workgroup
EmbeddedEmbedded Swiftswift.org/embedded
Standard library rewriteswift-foundationgithub.com/swiftlang/swift-foundation

Three core insights.

First, strict concurrency is the identity of Swift 6. async/await landed in Swift 5.5, the actor model stabilized in 5.7, strict concurrency arrived opt-in in 5.10. Swift 6.0 made it the default, and compiling old code suddenly emits hundreds or thousands of warnings at once. That migration cost is real — but once you pass through, you get a compile-time guarantee against data races. Apple internally is walking the same road, and externally large iOS shops like Airbnb, Lyft, and Uber are running multi-year migrations.

Second, Swift is increasingly moving outside Apple. Vapor has been holding up server-side Swift since 2016, but November 2024's launch of the Android Swift Working Group made the non-Apple track official. Embedded Swift appeared at the 2024 WWDC keynote with a demo running on STM32 with a 16KB binary. swift-foundation is the rewrite of Objective-C-based NSFoundation in pure Swift, in full swing since 2024.

Third, the tooling ecosystem has shifted from fragmentation to convergence. swift-format (Apple official) and SwiftFormat (Nick Lockwood) coexist, and SwiftLint (Realm) holds the linter chair, but Apple standardizing swift-syntax means everyone uses the same AST. CocoaPods → Carthage → SwiftPM migration is mostly complete, and SwiftPM is the default for new projects. Tuist filled the gap between SwiftPM and Xcode and has settled into monorepos and multi-target setups.


2. Swift 6.1 — complete mode + raw identifiers

Swift 6.1 was a maintenance + feature release that landed in spring 2025. Two core changes.

First, the strict concurrency "complete" mode is stable. Swift 6.0 turned strict concurrency on by default, but the project still picks where on the minimal/targeted/complete ladder to sit. In 6.1, complete mode's false positives and diagnostic quality improved significantly. Sendable inference in particular got smarter, so more legacy code can now be proved safe without explicit @Sendable annotations.

Second, raw identifiers. Identifiers wrapped in backticks can now contain spaces and special characters. Decisive when you want to name test functions in natural language.

import Testing

@Test func `a user receives a token after logging in`() async throws {
    let user = User(email: "test@example.com")
    let token = try await login(user)
    #expect(!token.isEmpty)
}

// Works for regular functions too
func `compute checksum for v2 protocol`(_ data: Data) -> UInt32 {
    // ...
}

Paired with swift-testing this lets you write Korean or Japanese test names naturally, which is part of why iOS teams at Kakao and LINE are likely adopters.

Smaller changes in Swift 6.1.

  • Stronger @MainActor inference — subclasses of UIView/UIViewController are inferred as @MainActor automatically.
  • Explicit nonisolated(unsafe) — the escape hatch for knowingly disabling isolation now has an explicit form.
  • typed throws GAfunc foo() throws(MyError). Type-safe error propagation, similar in spirit to Rust's Result.
  • package manager noncopyable types support~Copyable generics are now first-class in SPM package interfaces.
// typed throws
enum NetworkError: Error {
    case timeout
    case unauthorized
}

func fetch(_ url: URL) async throws(NetworkError) -> Data {
    // ...
}

// Caller catches exactly NetworkError
do {
    let data = try await fetch(url)
} catch .timeout {
    // ...
} catch .unauthorized {
    // ...
}

typed throws calls Java's checked exceptions to mind, but Swift's implementation is lighter — it's just a generic. The bare throws is modeled as sugar for throws(any Error).


3. Swift 6.2 preview — concurrency improvements

Swift 6.2 is in preview targeting GA in fall 2026. It ships in Xcode 17 beta. The headline direction is one thing — make strict concurrency feel more like a default than a feature.

The most common complaint about 6.0/6.1 has been "simple code suddenly gets data-race warnings." 6.2 sands those friction points down.

1) Expanded default @MainActor inference. Beyond UI code, SwiftUI Views, ViewModel patterns, and Combine publishers are inferred as @MainActor automatically. New projects will write almost entirely @MainActor code, and only when you explicitly mark nonisolated or another actor isolation does the code drop into a worker context.

2) Stronger Sendable inference. A struct or enum becomes Sendable automatically when all of its stored properties are Sendable. The change started in 6.1, but 6.2 extends it to cross-module inference.

3) Improved async let / TaskGroup diagnostics. The most common mistake is "capturing a value and passing it to a task where the value is not Sendable." 6.2 tracks more precisely which variable escapes to which task, and fix-its are friendlier.

4) Span / RawSpan types. Borrowed-view types analogous to Rust's &[T] and &str. Lighter than ArraySlice, enabling safe zero-copy data access.

// Swift 6.2 preview
extension Array {
    func sumFirstHalf() -> Element where Element: Numeric {
        let half: Span<Element> = self.span.prefix(self.count / 2)
        return half.reduce(0, +)
    }
}

5) C++ interop stabilization. Swift-to-C++ bidirectional interop gets another level of polish in 6.2. Dependency graphs, template instantiation, and RAII mapping smooth out. This is not just a tooling improvement — it's positioning Swift as a language you can incrementally introduce into an existing C++ codebase.

The slogan for 6.2 is "strict concurrency becomes invisible." Well-written code should let the developer write safe code with almost no isolation annotations at all.


4. SwiftUI 6 (iOS 18) — Mesh gradient / scroll position / View Transition

SwiftUI 6 shipped in fall 2024 alongside iOS 18 / macOS 15 / visionOS 2, and stability patches landed throughout 2025. The three most visible new features.

1) Mesh gradient. Place colors on a 2D mesh grid and interpolate between them. Far more expressive than linear or radial gradients — you can finally draw the smooth color transitions you usually saw only in Sketch or Figma, natively in SwiftUI.

import SwiftUI

struct MeshDemo: View {
    var body: some View {
        MeshGradient(
            width: 3,
            height: 3,
            points: [
                .init(0, 0), .init(0.5, 0), .init(1, 0),
                .init(0, 0.5), .init(0.5, 0.5), .init(1, 0.5),
                .init(0, 1), .init(0.5, 1), .init(1, 1),
            ],
            colors: [
                .red, .purple, .blue,
                .orange, .white, .cyan,
                .yellow, .green, .mint,
            ]
        )
        .ignoresSafeArea()
    }
}

2) Scroll position binding. Two-way binding between the ScrollView's scroll position and a @State value. Without resorting to the old imperative contentOffset API you can scroll to a specific row and observe where the user is currently scrolled — declaratively.

struct ScrollDemo: View {
    @State private var scrollPosition = ScrollPosition(idType: Int.self)

    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach(0..<100, id: \.self) { i in
                    Text("Row \(i)")
                        .id(i)
                }
            }
            .scrollTargetLayout()
        }
        .scrollPosition($scrollPosition)
        .safeAreaInset(edge: .top) {
            Button("Top") { scrollPosition.scrollTo(id: 0) }
        }
    }
}

3) View Transition. What people called "hero animation" — shared-element transitions between screens — landed cleanly without selectors. Pair matchedTransitionSource with navigationTransition and it just works inside NavigationStack navigation.

@Namespace var ns

NavigationLink(value: photo) {
    Image(photo.thumb)
        .matchedTransitionSource(id: photo.id, in: ns)
}
.navigationDestination(for: Photo.self) { photo in
    PhotoDetail(photo: photo)
        .navigationTransition(.zoom(sourceID: photo.id, in: ns))
}

4) Smaller things.

  • @Entry macro — define Environment keys in a single line.
  • TabView rewrite — sidebar adaptive, fluid customization.
  • Charts improvements — 3D charts, vector-based annotations.
  • Subview API — a new way to index child views, applicable to general view trees beyond ForEach.

After iOS 18.4, the Translation framework integrated with SwiftUI and added a view modifier that translates on-screen text on-device. It depends on Apple Intelligence so it doesn't run on every device — but for apps that handle Korean and Japanese it's compelling.


5. SwiftData — the Core Data successor

Core Data is Apple's ORM, shipped with macOS 10.4 Tiger in 2005. Solid, but full of old patterns like NSManagedObject and NSFetchRequest from the Objective-C era. SwiftData aims for the same chair as a Swift-native successor; it was announced at iOS 17 in 2023 and stabilized through 2024-2025. As of May 2026, SwiftData is the default for new projects.

The core of SwiftData — defining a class with the @Model macro turns it into a persistent class automatically.

import SwiftData
import SwiftUI

@Model
final class Note {
    var title: String
    var body: String
    var createdAt: Date
    @Relationship(deleteRule: .cascade) var tags: [Tag]

    init(title: String, body: String, tags: [Tag] = []) {
        self.title = title
        self.body = body
        self.createdAt = .now
        self.tags = tags
    }
}

@Model
final class Tag {
    @Attribute(.unique) var name: String
    init(name: String) { self.name = name }
}

Inside SwiftUI you read with @Query and write with modelContext.insert().

struct NoteList: View {
    @Query(sort: \Note.createdAt, order: .reverse) var notes: [Note]
    @Environment(\.modelContext) var modelContext

    var body: some View {
        List(notes) { note in
            VStack(alignment: .leading) {
                Text(note.title).font(.headline)
                Text(note.body).lineLimit(2)
            }
        }
        .toolbar {
            Button("Add") {
                modelContext.insert(Note(title: "New", body: ""))
            }
        }
    }
}

Under the hood Core Data is still running. SwiftData is just a Swift-native layer over Core Data — so incremental migration from a Core Data-based app is possible. iCloud sync (CloudKit) still works as is.

SwiftData's limitations — through 2025 the most common complaint was performance. Large datasets (100K+ rows) saw @Query evaluated on the main thread, blocking the UI, and the undo manager would unintentionally pile every change onto its stack. Patches through iOS 18.x made it much better, but for a large catalog app you might still consider Core Data directly.

Other options.

  • GRDB.swift — Swift-native ORM over SQLite. Light without the Core Data dependency.
  • Realm — stable since the MongoDB acquisition, but new adoption is dropping.
  • Supabase Swift SDK — when you want the backend bundled.
  • Drizzle ORM (server Swift side) — when handling Postgres on the server.

For small data in iOS apps (under 10MB, under 10K rows) SwiftData is the default. Above that, look at GRDB.


6. Vapor 4 — the server Swift standard

The de facto standard for server-side Swift is Vapor 4. First released in 2016, Vapor 4 embraced async/await in 2020, and as of May 2026 the 4.x major continues to evolve.

The appeal of Vapor — familiar routing reminiscent of Express/Koa, Fastify, NestJS combined with Swift's type safety.

import Vapor
import Fluent

struct TodoController: RouteCollection {
    func boot(routes: RoutesBuilder) throws {
        let todos = routes.grouped("todos")
        todos.get(use: index)
        todos.post(use: create)
        todos.group(":todoID") { todo in
            todo.get(use: show)
            todo.delete(use: delete)
        }
    }

    func index(req: Request) async throws -> [Todo] {
        try await Todo.query(on: req.db).all()
    }

    func create(req: Request) async throws -> Todo {
        let todo = try req.content.decode(Todo.self)
        try await todo.save(on: req.db)
        return todo
    }

    func show(req: Request) async throws -> Todo {
        guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else {
            throw Abort(.notFound)
        }
        return todo
    }

    func delete(req: Request) async throws -> HTTPStatus {
        guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else {
            throw Abort(.notFound)
        }
        try await todo.delete(on: req.db)
        return .noContent
    }
}

Vapor's building blocks.

  • routing — async-first handlers, parameter binding.
  • Fluent ORM — Postgres, MySQL, SQLite, MongoDB drivers.
  • Leaf — template engine (server-rendered HTML).
  • JWT — auth/identity.
  • Queues — background jobs, Redis-backed.
  • WebSocketKit — bidirectional communication.
  • OpenAPIKit / openapi-generator-swift — OpenAPI codegen.

Production usage — Vapor runs in production at places like Kodeco (formerly Ray Wenderlich), Transeo, and Emerge Tools, and Apple is known to use Vapor for some internal tooling. Traffic scale isn't quite Node/Go territory, but for teams that want Swift on both client and server it's a strong choice.


7. Hummingbird 2 (Apple-backed) — Swift Server Workgroup

Hummingbird is an alternative server framework built by Adam Fowler. In its 1.x days it was sometimes called "lightweight Vapor." With 2.0 in 2024 it gained standing as a candidate backed by Apple's Swift Server Workgroup (SSWG).

Three appeals of Hummingbird 2.

1) Fewer dependencies. Where Vapor bundles a full stack — Fluent, Leaf, JWT — Hummingbird offers just routing + middleware + HTTP handling. ORM, templating, and auth are assembled from separate packages. Similar to the Express vs NestJS relationship.

2) Native Swift Concurrency. Designed from day one on top of async/await and structured concurrency. It runs on SwiftNIO but doesn't expose NIO's EventLoopFuture directly.

3) AWS Lambda friendly. Cold starts are fast and binary sizes small. It pairs nicely with swift-aws-lambda-runtime — Hummingbird is increasingly the default in the Swift on Lambda story.

import Hummingbird

let router = Router()
router.get("/") { _, _ in
    "Hello, Hummingbird 2"
}
router.get("/users/:id") { req, ctx in
    let id = try ctx.parameters.require("id", as: Int.self)
    return User.fetch(id: id)
}

let app = Application(
    router: router,
    configuration: .init(address: .hostname("0.0.0.0", port: 8080))
)
try await app.runService()

Vapor vs Hummingbird decision guide.

ItemVapor 4Hummingbird 2
PositioningFull-stack frameworkMicro router
ORMFluent bundledGRDB / others separate
async/awaitInside backward compatibilityNative design
LambdaPossible but heavyFast cold start
Learning curveLow (Express-like)Low (smaller)
CommunityLarge (older)Growing
Apple backingUnofficialSSWG official

Large monoliths or server-rendered HTML apps — Vapor. Microservices, Lambda, minimal binary — Hummingbird. API-only with no SSR — both work well.


8. Tuist + Mint + swift-package-manager — build and tooling

SwiftPM (swift-package-manager) is Apple's official package manager. The CocoaPods/Carthage era is essentially over and SwiftPM is the default in new 2026 projects. You declare dependencies in Package.swift, and both Xcode and the CLI understand it.

// swift-tools-version: 6.1
import PackageDescription

let package = Package(
    name: "MyLib",
    platforms: [.iOS(.v17), .macOS(.v14)],
    products: [
        .library(name: "MyLib", targets: ["MyLib"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-collections.git", from: "1.1.0"),
    ],
    targets: [
        .target(name: "MyLib", dependencies: [
            .product(name: "Collections", package: "swift-collections"),
        ]),
        .testTarget(name: "MyLibTests", dependencies: ["MyLib"]),
    ]
)

Limitation — SwiftPM is good for simple library packages, but for iOS apps with the storyboard/xcassets/info.plist/scheme web tangled together it falls short. That gap is where Tuist came in.

Tuist generates Xcode projects from Project.swift (a Tuist-specific DSL, not SwiftPM). In big monorepos it splits modules finely, expresses inter-module dependencies as code, and supports caching and incremental builds.

// Project.swift
import ProjectDescription

let project = Project(
    name: "MyApp",
    targets: [
        .target(
            name: "MyApp",
            destinations: .iOS,
            product: .app,
            bundleId: "com.example.MyApp",
            infoPlist: .extendingDefault(with: [
                "CFBundleShortVersionString": "1.0.0",
            ]),
            sources: ["Sources/**"],
            resources: ["Resources/**"],
            dependencies: [
                .target(name: "Core"),
                .target(name: "Network"),
            ]
        ),
        .target(name: "Core", destinations: .iOS, product: .framework, bundleId: "com.example.Core", sources: ["Modules/Core/**"]),
        .target(name: "Network", destinations: .iOS, product: .framework, bundleId: "com.example.Network", sources: ["Modules/Network/**"], dependencies: [.target(name: "Core")]),
    ]
)

Tuist has cemented itself at places like Kakao, LINE, and Mercari with 100+ module monorepos. tuist generate creates the Xcode project and tuist build runs cached incremental builds. In 2024 Tuist Cloud (since folded into Tuist itself) added team-wide shared build cache.

Mint installs CLI tools written in Swift. If you install SwiftLint, SwiftFormat, swiftgen, xcodegen, and Sourcery via Mint instead of Homebrew, you can pin the team's versions with a Mintfile.

# Mintfile example
realm/SwiftLint@0.59.1
nicklockwood/SwiftFormat@0.55.0
yonaskolb/XcodeGen@2.42.0

# Install
mint bootstrap

# Run
mint run swiftlint

Larger teams typically combine all three — SwiftPM (libraries) + Tuist (project generation) + Mint (CLI tools) — as the standard recipe.


9. swift-syntax / swift-format / SwiftLint / SwiftFormat

These four tools all belong to the same family in that they "handle Swift source code."

swift-syntax — Apple's official AST library. Exposes the same lexer/parser that the swift compiler uses. Essential when writing macros (@Macro, Swift 5.9+). Lets user code extend compiler features like ResultBuilder and Codable.

swift-format — Apple's official formatter. Apple absorbed Google's swift-format and moved it under the swiftlang/ org. Follows a fixed style guide (largely Apple style) with few options. swift-syntax based.

SwiftFormat — community formatter by Nick Lockwood. Many options — over 100 rules to toggle. Strong fit for incrementally tidying a legacy codebase.

SwiftLint — linter by Realm. Enforces JonAS/Mac/iOS standard coding conventions. Not a formatter (some auto-fix exists but the primary purpose is checking). 200+ rules, custom rules supported.

A one-table summary.

ToolRoleOptionsApple officialAuto-fix
swift-syntaxAST libraryn/aYesn/a
swift-formatFormatterFewYesYes
SwiftFormatFormatterManyNoYes
SwiftLintLinterManyNoPartial

Practical combinations.

  • New project — swift-format (follow Apple style) + SwiftLint (checks).
  • Legacy project — SwiftFormat (preserve old style via options) + SwiftLint.
  • Macros / metaprogramming — swift-syntax directly.

SwiftLint config example.

disabled_rules:
  - trailing_whitespace
opt_in_rules:
  - empty_count
  - missing_docs
included:
  - Sources
excluded:
  - Tests/Resources
  - .build
line_length:
  warning: 120
  error: 200
identifier_name:
  min_length: 2
  excluded:
    - id
    - i
    - x
    - y
custom_rules:
  no_print:
    name: "No print()"
    regex: "print\\("
    message: "Use Logger instead of print()"
    severity: error

The standard CI setup runs SwiftLint with --strict and swift-format or SwiftFormat with --lint and blocks the PR on failures.


10. swift-testing (new in Swift 6.0) — replacing XCTest

XCTest is a relic of the Objective-C era. func test... naming, XCTAssertEqual() helpers, instance-time lifecycle — all OOP-first design. swift-testing is the new testing framework that shipped formally with Swift 6.0 (September 2024) and embraces Swift's macro system.

Basic comparison.

// XCTest (the old way)
import XCTest

final class CalculatorTests: XCTestCase {
    func testAddition() {
        let result = Calculator.add(2, 3)
        XCTAssertEqual(result, 5)
    }
    func testDivision() throws {
        let result = try Calculator.divide(10, 2)
        XCTAssertEqual(result, 5)
    }
}

// swift-testing (Swift 6.0+)
import Testing

@Test func addition() {
    let result = Calculator.add(2, 3)
    #expect(result == 5)
}

@Test func division() throws {
    let result = try Calculator.divide(10, 2)
    #expect(result == 5)
}

The difference jumps out. No need to memorize a different helper per assertion shape like XCTAssertEqual(a, b), and #expect(...) is a macro that automatically decomposes the full expression on failure — similar in spirit to Rust's assert! or Catch2's REQUIRE.

Parameterized tests.

@Test(arguments: [(2, 3, 5), (10, -3, 7), (0, 0, 0)])
func addition(a: Int, b: Int, expected: Int) {
    #expect(Calculator.add(a, b) == expected)
}

Conditional execution.

@Test(.enabled(if: ProcessInfo.processInfo.environment["CI"] == nil))
func localOnlyTest() {
    // Local machines only
}

Async tests are just an async away.

@Test func fetchesUser() async throws {
    let user = try await api.fetchUser(id: 1)
    #expect(user.name == "Alice")
}

Coexistence with XCTest — swift-testing runs in the same binary as XCTest. You can mix import Testing and import XCTest in the same target. So you don't have to migrate everything at once; new tests can use swift-testing while old tests stay put.

XCTest isn't going away. UI tests (XCUIApplication) and performance tests (measure { }) remain XCTest territory. swift-testing targets unit and integration tests.


11. Android Swift Working Group (2024.11) — Swift on Android

In November 2024, swift.org ran a short but decisive post — "the Android Swift Working Group has been formed." Apple, Google (on the Android side), and the community would together make Swift a first-class citizen on Android.

Background. There were earlier attempts at Swift on Android. Readdle famously wrote Android apps internally in Swift, commercial tools like scade.io existed, and swift-corelibs-foundation partially supported the Android target. All were unofficial and experimental, with parts of the standard library missing, NDK integration incomplete, and the App-Store-vs-Play-Store path blocked.

Goals of the Android Swift WG (disclosed at launch in November 2024).

  1. Official toolchain — distribute Android-target binaries directly from swift.org.
  2. Standard library compatibility — Foundation, Network, Concurrency all work on Android.
  3. JNI bridge — call Swift from Kotlin/Java and vice versa.
  4. Android-specific libraries — Swift-native bindings for core Android APIs like Activity and Intent.
  5. Build integration — a standard for building Swift modules inside Gradle.

Status as of May 2026 — a year and a half after the WG launched, experimental toolchains are distributed and hello world runs reliably. Foundation and Concurrency mostly work. We're not at the point of writing real production apps yet — but by 2027 it could be a viable option competing with Kotlin Multiplatform.

Expectation setting — "let's write Android apps only in Swift" isn't the real Swift on Android scenario. "Let's reuse iOS business logic on Android" is more realistic. UI is SwiftUI (iOS) + Compose (Android), and only the model/network/domain logic is shared in Swift.

Alternatives — Kotlin Multiplatform is already doing the same thing, more mature thanks to JetBrains backing. Compose Multiplatform now supports iOS, expanding the territory. For Swift on Android to take root it needs to offer something KMP doesn't — what exactly that is will become clear around 2027.


12. swift-foundation rewrite (open source) + Embedded Swift

swift-foundation is the project rewriting Foundation (NSString, NSDate, URLSession, JSONSerialization, etc.) in pure Swift without Objective-C dependencies. Developed at github.com/swiftlang/swift-foundation.

Why rewrite. The old Foundation had two versions. Apple Darwin used Objective-C-based NSFoundation; Linux used swift-corelibs-foundation (C-based). They promised the same API but behaved subtly differently — date formatting, URL parsing, JSON encoding all varied across OSes, and bugs lived on only one side.

The promise of swift-foundation — the same code runs on every OS and behaves the same way. Darwin is gradually switching to swift-foundation too. In 2024-2025 core types like Calendar, Date, JSONEncoder, and URL were migrated; in 2026 URLSession and FileManager are mid-migration.

Impact — biggest on Linux and server Swift. Code that ran fine on macOS used to break randomly on Linux; with swift-foundation those incidents nearly vanish. Embedded Swift and Android Swift get to use the same Foundation, which is a major shift.


Embedded Swift is a new mode introduced at the 2024 WWDC keynote. Regular Swift carries ARC, dynamic dispatch, exception handling, and a Foundation dependency that make it too heavy for microcontrollers like STM32 or ESP32. Embedded Swift strips down a subset of the language so it can run on those targets and produce small binaries.

What's missing.

  • Parts of the standard library — nearly all of Foundation, Combine, parts of the Concurrency runtime.
  • Dynamic features — runtime metadata reflection (Mirror), full dynamic decoding in JSONDecoder.
  • Exceptionsthrows works, but no runtime exception unwinding.

What remains.

  • Language basics — struct, enum, class, generic, protocol.
  • Ownership system~Copyable, ~Escapable.
  • Concurrency subset — a lightweight async/await (embedded mode).
  • C interop — works as is.

Use cases — microcontroller firmware, IoT devices, some drivers and kernel modules. Apple is known to be rewriting some SecureEnclave components in Embedded Swift. Outside Apple there are demos running Embedded Swift on ESP32 boards and Raspberry Pi Pico samples in swift-embedded-examples.

// Embedded Swift example — Raspberry Pi Pico LED blink
import Pico

@main struct App {
    static func main() {
        let led = GPIO(pin: 25, direction: .output)
        while true {
            led.high()
            sleep(milliseconds: 500)
            led.low()
            sleep(milliseconds: 500)
        }
    }
}

Competition with Rust on embedded (embedded-hal, esp-rs) has begun. Rust got a 5-6 year head start — but with Apple's weight behind it, how far Embedded Swift goes will be one of the more interesting threads to watch.


13. Concurrency — actors / async / await / Sendable

Swift Concurrency began in 5.5 (2021) and completed in stages through 5.7 (actors), 5.9 (macros), 6.0 (strict), and 6.1 (complete). Four core concepts.

1) async/await. Write asynchronous code as if it were synchronous. Promise/Future are not exposed explicitly.

func fetchUser(id: Int) async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// Call site
let user = try await fetchUser(id: 1)

2) actor. A stateful object. Access to its internal data is serialized, blocking data races.

actor Counter {
    private var count = 0
    func increment() { count += 1 }
    func value() -> Int { count }
}

let counter = Counter()
await counter.increment()  // await required from outside the actor
let v = await counter.value()

3) Sendable. A marker protocol for "a type that can be safely shared across threads." The compiler uses this marker to check value passing across actor boundaries.

struct UserInfo: Sendable {
    let id: Int
    let name: String  // String is automatically Sendable
}

class MutableBox {
    var value: Int = 0  // class with mutable property → cannot be Sendable
}
// MutableBox is not Sendable → compiler error when sent across actor boundary

4) Strict Concurrency. A compiler mode that decides how strictly to check Sendable. "complete" became the default in Swift 6.0, and false positives dropped considerably in 6.1.

# Enable in Package.swift
.target(
    name: "MyLib",
    swiftSettings: [
        .enableExperimentalFeature("StrictConcurrency"),
    ]
)

@MainActor. The compiler enforces the convention that all UI code runs on the main thread.

@MainActor
class ViewModel: ObservableObject {
    @Published var users: [User] = []

    func load() async {
        let result = try? await api.fetchUsers()  // runs on a worker actor
        self.users = result ?? []  // hops back to the main actor
    }
}

Here api.fetchUsers() runs on a non-MainActor context, and when assigning to self.users execution hops back to the main thread automatically. In C++ or Java you'd have to write dispatch_async(main_queue, ^{...}) yourself — Swift's compiler handles it.

Region-based isolation (Swift 6.0+). A new mechanism that lets a single instance be "sent" from one task to another. Where it used to require Sendable to cross an actor boundary, region isolation lets a value cross if "we can prove the value is only used in one place right now."

func process() async {
    let data = NonSendableData()
    await someActor.use(data)  // error in Swift 5.x; allowed in Swift 6.x with region isolation
    // But: using `data` after this point becomes a compile error
}

This is the single biggest improvement that reduces strict concurrency's false positives.


14. Observation + Macros — iOS 17+ features

The Observation framework is the new reactive system introduced in iOS 17 (2023). It replaces the older @Published/Combine-based ObservableObject pattern more lightly.

Old way (Combine ObservableObject).

class UserStore: ObservableObject {
    @Published var users: [User] = []
    @Published var isLoading = false
}

struct UserList: View {
    @StateObject var store = UserStore()
    var body: some View {
        if store.isLoading { ProgressView() }
        else { List(store.users) { Text($0.name) } }
    }
}

New way (Observation).

@Observable
class UserStore {
    var users: [User] = []
    var isLoading = false
}

struct UserList: View {
    @State var store = UserStore()
    var body: some View {
        if store.isLoading { ProgressView() }
        else { List(store.users) { Text($0.name) } }
    }
}

Differences.

  • No @Published needed — Observation handles it via macro.
  • No ObservableObject conformance needed.
  • @StateObject simplifies to @State.
  • Fine-grained invalidation — where previously any published property change re-rendered the whole view, Observation tracks which property a view actually reads and invalidates only that. Major performance win.

Under the hood, the @Observable macro generates KeyPath-based tracking code inside the class. It's built on swift-syntax and users can extend it themselves.


Macros (Swift 5.9+). Macros are a mechanism for generating code at compile time. Unlike C macros, they are not text substitution — they're AST transformations. Functions that take ASTs exposed by swift-syntax and return new ASTs.

Two kinds of macros.

1) Freestanding macros — invoked like #stringify.

let (result, code) = #stringify(2 + 3)
// After compile: (5, "2 + 3")

2) Attached macros — attached to a declaration like @AddCompletionHandler.

@AddAsync
func fetch(completion: @escaping (Result<Data, Error>) -> Void) {
    // ...
}
// Macro auto-generates:
// func fetch() async throws -> Data { ... }

The standard library and SDKs use macros aggressively.

  • @Observable — what we saw above.
  • @Model (SwiftData) — generates the persistent class.
  • #expect (swift-testing) — assertion macro.
  • @Entry (SwiftUI 6) — Environment key definition.
  • #Predicate (SwiftData/Foundation) — type-safe query.

Writing a user macro (sketch).

import SwiftSyntax
import SwiftSyntaxMacros

public struct StringifyMacro: ExpressionMacro {
    public static func expansion(
        of node: some FreestandingMacroExpansionSyntax,
        in context: some MacroExpansionContext
    ) -> ExprSyntax {
        guard let argument = node.argumentList.first?.expression else {
            fatalError("compiler bug: the macro does not have any arguments")
        }
        return "(\(argument), \(literal: argument.description))"
    }
}

Macros live in a separate target (.macro(...)) and build as a compiler plugin. They're isolated from regular code so they guarantee compile-time safety.

Macro tradeoff — compile time goes up (swift-syntax is a heavy dependency). Popular macros are increasingly shipped as pre-compiled binaries.


15. Korea / Japan — Kakao, LINE, Mercari, Cookpad, pixiv

Swift is the default language for iOS teams in Korea and Japan. Who uses it how — synthesized from public conferences, blog posts, and job listings.

Korea.

  • Kakao — iOS apps (KakaoTalk, Kakao Bank, Kakao Map, KakaoWebtoon) are nearly all Swift. KakaoTalk is a large monorepo with well over 100 modules and is known for its Tuist adoption. They're walking the staged RxSwift → Combine → Swift Concurrency migration. The internal "if(kakao)" conference shares SwiftUI/SwiftData adoption retrospectives annually.
  • LINE — the LINE app from the Tokyo HQ is Swift-based. Korea's LINE Plus is Swift standard too. Known as one of the teams quick to try swift-testing.
  • Toss — all iOS is Swift. Adopted Tuist plus modularization plus Combine plus some SwiftUI. Distributes design system and component libraries internally as SwiftPM packages.
  • Coupang — iOS app in Swift. A migration case with some old ObjC still around.
  • Karrot — Swift plus aggressive SwiftUI adoption. Published an internal RFC evaluating SwiftData adoption.
  • Naver — Naver app, Naver Map, Webtoon, V LIVE, and friends are iOS in Swift. Known for cleaning up internal libraries into SwiftPM packages.

Japan.

  • Mercari — iOS app in Swift; some microservices being evaluated on Vapor or Hummingbird. Published internal swift-testing migration guides.
  • Cookpad — iOS app in Swift. Shared SwiftUI adoption stories at iOSDC Japan.
  • CyberAgent (ABEMA, AmebaTV) — ABEMA iOS is Swift + SwiftUI. Many internal iOS apps use Tuist. Many CyberAgent iOS engineers contribute actively to swift.org and iOSDC.
  • pixiv — iOS app in Swift. Sister apps like pixivFANBOX, pixivSketch, and BOOTH are also Swift.
  • DeNA — all internal iOS apps are Swift. Maintains an internal Swift toolchain mirror.
  • Yahoo! Japan (LY Corporation) — Yahoo!, Yahoo! News, Yahoo! Transit and friends are Swift.

Common patterns.

  • CocoaPods to SwiftPM migration is nearly done.
  • Combine to Swift Concurrency migration ongoing. New code is async/await first.
  • UIKit + SwiftUI hybrid — new screens in SwiftUI, old screens in UIKit. Incremental migration.
  • Tuist adoption — basically any team with 50+ modules.
  • XCTest to swift-testing — migration starting in 2025-2026.

In both Korea and Japan, iOS hiring increasingly lists "Swift Concurrency experience," "production SwiftUI experience," and "modularization/Tuist experience" as essential keywords.


16. Who should pick Swift — iOS / Apple ecosystem / server / embedded

Recommendations by domain.

iOS / macOS / visionOS / watchOS / tvOS apps.

  • Nearly default. Swift + SwiftUI or Swift + UIKit. New projects are SwiftUI first.
  • If there's a giant legacy ObjC codebase, incremental migration. Apple itself walks the same road.
  • Flutter / React Native / Kotlin Multiplatform exist as alternatives — but when you actually need native experience and the newest OS APIs, Swift is default.

Server.

  • Vapor — full-stack web apps, server-rendered HTML, want the familiar Express-like experience.
  • Hummingbird — microservices, AWS Lambda, want minimal dependencies.
  • Swift isn't a server standard the way Go, Rust, or Node are. When would you bother using Swift on the server? When you want to share models and domain logic with the iOS team. A company doing both iOS and server in Swift consolidates code reuse and the hiring pool.

Linux / containers.

  • Containerized microservices via Vapor or Hummingbird are possible. With distroless base images you're in the 50-100MB neighborhood.
  • Binary size is bigger than Go or Rust, but Swift stripped binaries are workable.

Android.

  • Not recommended for production in 2026. Kotlin Multiplatform is more stable.
  • If the goal is reusing iOS business logic on Android — wait on the Android Swift WG and re-evaluate after 2027.

Embedded / IoT.

  • Embedded Swift runs experimentally fine on ESP32, STM32, Raspberry Pi Pico.
  • For production, Rust (embedded-hal) or C remain the defaults.
  • Scenarios where Swift makes sense — firmware for Apple accessories, AirTag-style devices. Otherwise it needs more time.

ML / data.

  • Python is default. Swift only when calling Core ML models on device.
  • Swift for TensorFlow shut down. Unlikely to come back.

Scripting / CLI.

  • swift-argument-parser is excellent for CLIs.
  • That said, startup time lags Python and Node, and single-binary distribution comes via SwiftPM build into a stripped binary.
  • Great choice for macOS dev tools. For cross-platform CLIs, Go and Rust still win.

So the decisive reasons to pick Swift.

  1. You're building an iOS or macOS app — default with no doubt.
  2. You're going deep into Apple platforms — visionOS, watchOS, tvOS are essentially Swift-only.
  3. You want strict concurrency seriously — Rust-like safety without GC or lifetime overhead.
  4. You love type-safe SwiftUI declarative UI — many find it more familiar with a cleaner API than Compose.
  5. The iOS team wants to write server code too — Vapor/Hummingbird for internal standardization.

Reasons not to pick Swift.

  1. Windows desktop is your main target — Swift runs on Windows but isn't a first-class citizen.
  2. You only do cross-platform mobile — Flutter, React Native, and Kotlin Multiplatform are more mature.
  3. Your server domain standardized on another language — if the team already lives in Go, Node, or Java, there's little reason to switch.
  4. ML/data — Python.
  5. You need maximum safety in systems programming — Rust.

The Swift of 2026 — default on Apple platforms, carving out its own space on the server, and still working to deliver on its promises in Android and embedded. The next 1-2 years will decide the fate of Swift outside Apple.


References