This episode takes Swift beyond the Apple ecosystem: an introduction to server-side Swift with Vapor, Kitura, and SwiftNIO, a comparison of use cases with other platforms, cross-platform Swift packages, and running Swift on Linux and in Docker for production.

Since Swift became open source in 2015, the language has no longer belonged to Apple alone. Episode 19 covers cross-platform and server-side Swift: using Swift for backends with frameworks like Vapor and SwiftNIO, running it on Linux and in Docker, and placing it in the right use cases.
One language for client and server brings real advantages: data models and business logic can be shared, and developers don't have to switch mental models between languages. For those who already master Swift, this is an extra superpower.
Vapor is the most popular Swift web framework, offering routing, middleware, templating, and database integration in one ecosystem. Its concepts are similar to Express in Node.js or Gin in Go:
import Vapor
func routes(_ app: Application) throws {
app.get("health") { req in
return "OK"
}
app.get("halo", ":nama") { req -> String in
let nama = req.parameters.get("nama") ?? "dunia"
return "Halo, \(nama)!"
}
}app.get("halo", ":nama"){ ... } registers a handler for a route with dynamic parameters. Vapor is built on top of SwiftNIO, so it supports high concurrency with low resource usage.
SwiftNIO is a low-level framework for asynchronous, event-driven networking — the foundation of Vapor. It gives you full control over protocols, making it suitable for custom servers and proxies. Kitura, IBM's framework, is now in maintenance mode with migration recommended toward Vapor or SwiftNIO — evidence that the server-side Swift ecosystem keeps consolidating.
Server-side Swift is strongest in the following use cases:
Conversely, if library ecosystem and speed of building are the top priorities, languages with a longer backend track record like Go or Node may be faster. Choose based on your team's and project's needs, not trends.
The core strength of one language is the cross-platform package: the same library used in an iOS app and on a server. The key is depending on cross-platform APIs — Foundation, SwiftNIO, and pure Vapor libraries:
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "IntiBisnis",
platforms: [.macOS(.v13), .iOS(.v16)],
products: [
.library(name: "IntiBisnis", targets: ["IntiBisnis"])
],
targets: [
.target(name: "IntiBisnis")
]
)platforms: [.macOS(.v13), .iOS(.v16)] declares the platforms the package supports. The code in IntiBisnis uses only Foundation, so it runs on both iOS and Linux servers — domain models and validation become a single source of truth.
To be genuinely cross-platform, avoid APIs that only exist on Apple platforms, such as UIKit and Core Data, in the core package. Split them into separate targets: the core library stays purely cross-platform, while platform-specific integration lives in the app target.
Swift runs fully on Linux with the official toolchain from swift.org. Installation varies by distribution; once installed, all the commands you already know work the same:
swift --version
swift build
swift testswift build on Linux builds the package identically to macOS — no extra configuration for portability. This is what makes Swift well-suited as a server language on any Linux machine.
For reproducible deployment, wrap the Swift server in a Docker image:
FROM swift:6.0 AS builder
WORKDIR /app
COPY Package.swift Package.resolved ./
COPY Sources ./Sources
RUN swift build -c release
FROM swift:6.0-slim
WORKDIR /app
COPY --from=builder /app/.build/release/App /app/
EXPOSE 8080
CMD ["./App"]FROM swift:6.0 AS builder uses the official builder image, and FROM swift:6.0-slim the leaner runtime image. The build runs with swift build -c release, and the result is copied into the runtime image.
Build and run the container:
docker build -t app-swift .
docker run -p 8080:8080 app-swiftdocker build -t app-swift . builds the image from the Dockerfile, and docker run -p 8080:8080 app-swift runs the server on port 8080. This container runs the same on a laptop, staging, and production — consistent deployment for episode 20.
Info
When building Swift images, cache the dependency layer by copying Package.swift and Package.resolved before the source code — code changes won't trigger a re-resolve of dependencies, speeding up build iteration.
Key takeaways:
In the next episode, episode 20, we'll cover deployment and app distribution — distributing iOS apps through the App Store, beta testing with TestFlight, deploying to macOS, watchOS, and tvOS, plus code signing, notarization, and release management. Your work reaches users!