SwiftChatApp
A primitive chat app utilizing SwiftUI and WebSockets. Both server and client!
Install / Use
/learn @frzi/SwiftChatAppREADME
A simple chat app with SwiftUI and WebSockets - or: Swift in the back, Swift in the front!
Creating a very primitive chat app in SwiftUI, while using Swift and WebSockets to create the chat server. It's Swift from top to bottom, bay-bee!

Index
- Introduction
- Creating the server
- Creating the app
- Sending and receiving messages
- Adding user information
- Recap
- Final words
- Final notes
- Appendix A: running on physical device
Introduction
In this tutorial we'll make a rather primitive, but functional chat app. The app will run on iOS or macOS - or both! The beauty of SwiftUI is how little effort it takes to make a multiplatform app.
Of course, a chat app will have very little use without a server to talk to. Hence we'll be making a very primitive chat server as well, utilizing WebSockets. Everything will be built in Swift and run locally on your machine.
This tutorial assumes you already have a bit of experience developing iOS/macOS apps using SwiftUI. Although concepts will be explained as we go, not everything will be covered in depth. Needless to say, if you type along and follow the steps, by the end of this tutorial you'll have a working chat app (for iOS and/or macOS), that communicates with a server that you also made! You will also have a basic understanding of concepts like server-side Swift and WebSockets.
If none of that interests you, you can always scroll to the end and download the final source code!
Quick summary of what's to come
In short, we will start by making a very simple, plain, featureless server. We'll build the server as a Swift Package, then add the Vapor web framework as a dependency. This will help us setup a WebSocket server with just a few lines of code.
Afterwards we will start building the frontend chat app. Quickly starting with the basics, then adding features (and necessities) one by one.
Most of our time will be spent working on the app, but we'll be going back and forth between the server code and the app code as we add new features.
Requirements
- macOS 10.15+
- Xcode 12 beta 5+
Optional
- macOS 11 beta
(if you want to run the app on macOS) - iPhone/iPad running iOS 14 beta 5+
(if you want to run the app on a physical device)
Let's begin!
Creating the server
Open Xcode 12 and start a new project (File > New Project). Under Multiplatform select Swift Package.

Call the Package something logical - something self explanatory - like "ChatServer". Then save it wherever you like.
Swift Package?
When creating a framework or multiplatform software (e.g. Linux) in Swift, Swift Packages are the preferred way to go. They're the official solution for creating modular code that other Swift projects can easily use. A Swift Package doesn't necessarily have to be a modular project though: it can also be a stand-alone executable that simply uses other Swift Packages as dependencies (which is what we're doing).
It may have occurred to you that there's no Xcode project (
.xcodeproj) present for the Swift Package. To open a Swift Package in Xcode like any other project, simply open thePackage.swiftfile. Xcode should recognize you're opening a Swift Package and opens the entire project structure. It will automatically fetch all the dependencies at the start.You can read more about Swift Packages and Swift Package Manager on the official Swift website.
Setup Package.swift
To handle all the heavy lifting of setting up a server, we'll be using the Vapor web framework. Vapor comes with all the necessary features to create a WebSocket server.
WebSockets?
To provide the web with the ability to communicate with a server in realtime, WebSockets were created. It's a well described spec for safe realtime (low-bandwidth) communication between a client and a server. E.g.: multiplayer games and chat apps. Those addictive in-browser multiplayer games you've been playing on valuable company time? Yup, WebSockets!
However, if you wish to do something like realtime video streaming you're best looking for a different solution. 🙂
Though we're making an iOS/macOS chat app in this tutorial, the server we're making can just as easily talk to other platforms with WebSockets. Indeed: if you want you could also make an Android and web version of this chat app, talking to the same server and allowing for communication between all platforms!
Vapor?
The internet is a complex series of tubes. Even responding to a simple HTTP request requires some serious amount of code. Luckily, experts in the field have developed open source web frameworks that do all the hard work for us for decades now, in various programming languages. Vapor is one of them, and it's written in Swift. It already comes with some WebSocket capabilities and it's exactly what we need.
Vapor isn't the only Swift powered web framework though. Kitura and Perfect are also well known frameworks. Though Vapor is arguably more active in its development.
Xcode should open the Package.swift file by default. This is where we put general information and requirements of our Swift Package.
Before we do that though, look in the Sources/ChatServer folder. It should have a ChatServer.swift file. We need to rename this to main.swift. Once that's done, return to Package.swift.
Under products:, remove the following value:
.library(name: "ChatServer", targets: ["ChatServer"])
... and replace it with:
.executable(name: "ChatServer", targets: ["ChatServer"])
After all, our server isn't a Library. But a stand-alone executable, rather. We should also define the platforms (and minimum version) we expect our server to run on. This can be done by adding platforms: [.macOS(v10_15)] under name: "ChatServer":
name: "ChatServer",
platforms: [
.macOS(.v10_15),
],
All this should make our Swift Package 'runnable' in Xcode.
Alright, let's add Vapor as a dependency. In dependencies: [] (which should have some commented-out stuff), add the following:
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0")
When saving the Package.swift file, Xcode should start automatically fetching the Vapor dependencies with verison 4.0.0 or newer. As well as all its dependencies.
We just have to make one more adjustment to the file while Xcode is doing its thing: adding the dependency to our target. In targets: you will find a .target(name: "ChatServer", dependencies: []). In that empty array, add the following:
.product(name: "Vapor", package: "vapor")
That's it. Our Package.swift is done. We've described our Swift Package by telling it:
- It's an executable, not a library
- To import the Vapor web framework dependency (and all its dependencies)
- Link the Vapor dependency to our executable, making it accessible in our code
The final Package.swift should look like this(-ish):
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "ChatServer",
platforms: [
.macOS(.v10_15),
],
products: [
.executable(name: "ChatServer", targets: ["ChatServer"])
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0")
],
targets: [
.target(
name: "ChatServer",
dependencies: [
.product(name: "Vapor", package: "vapor")
]),
]
)
Now, it's finally time for...
Writing some actual code
In Xcode, open Sources/ChatServer/main.swift and delete everything in there. It's worthless to us. Instead, make main.swift look like this:
import Vapor
var env = try Environment.detect() // 1
let app = Application(env) // 2
defer { // 3
app.shutdown()
}
app.webSocket("chat") { req, client in // 4
print("Connected:", client)
}
try app.run() // 5
💥 Bam! That's all it takes to start a (WebSocket) server using Vapor. Look at how effortless that was.
- First we make a default Environment configuration.
- We initialize a Vapor Application instance and pass it the Environment.
- Register a
deferand call.shutdown()which will perform any cleanup when exiting the program. - Start listening to any incoming WebSocket connections on
/chat. - Acually start the Vapor Application instance.
Now ▶️ run the program in Xcode and grab something to drink. Building the first time takes a while as Xcode will need to build all those Vapor dependencies first. (But only once)
Once the program has successfully run, you may not see anything resembling an app. That's because server software don't tend to have graphical user interfaces. But rest assured, the program is alive and well in the background, spinning its wheels. The Xcode console should show the following message, however:
notice codes.vapor.application : Server starting on http://127.0.0.1:8080
This mean
Related Skills
YC-Killer
2.7kA library of enterprise-grade AI agents designed to democratize artificial intelligence and provide free, open-source alternatives to overvalued Y Combinator startups. If you are excited about democratizing AI access & AI agents, please star ⭐️ this repository and use the link in the readme to join our open source AI research team.
groundhog
399Groundhog's primary purpose is to teach people how Cursor and all these other coding agents work under the hood. If you understand how these coding assistants work from first principles, then you can drive these tools harder (or perhaps make your own!).
sec-edgar-agentkit
10AI agent toolkit for accessing and analyzing SEC EDGAR filing data. Build intelligent agents with LangChain, MCP-use, Gradio, Dify, and smolagents to analyze financial statements, insider trading, and company filings.
last30days-skill
5.9kAI agent skill that researches any topic across Reddit, X, YouTube, HN, Polymarket, and the web - then synthesizes a grounded summary
