Introduction: Why Does a Swift Developer Need Databases?
Modern iOS and macOS applications rarely do without data storage. Whether it's a to-do list, a user profile, or a product catalog — data needs to be saved and retrieved somewhere. Swift, as the main language of the Apple ecosystem, provides powerful tools for working with databases. In this article, we will look at how a beginner developer can connect and perform CRUD operations (Create, Read, Update, Delete) with two popular systems: the relational PostgreSQL and the document-oriented MongoDB.
We will use the server-side framework Vapor (based on SwiftNIO) for working with PostgreSQL, and the popular driver MongoKitten for MongoDB. Both options are excellent for Swift backend development. If you are just starting out — don't worry: all the code will be simple and well-explained.
1. PostgreSQL and Swift: The Classic Relational Database
PostgreSQL is a powerful relational database with SQL support. For Swift, the best way to interact is the Vapor framework and its ORM Fluent. Fluent allows you to work with tables as if they were regular Swift structures.
1.1. Setting Up a Vapor Project
First, install Vapor Toolbox and create a project:
brew install vaporvapor new MyAppcd MyAppAdd the dependency for PostgreSQL in Package.swift:
dependencies: [ .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"), .package(url: "https://github.com/vapor/fluent.git", from: "4.0.0"), .package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0")]1.2. Model and Migration
Let's create a simple User model:
import Fluentimport Vapor
final class User: Model, Content { static let schema = "users" @ID(key: .id) var id: UUID? @Field(key: "name") var name: String @Field(key: "email") var email: String init() { } init(id: UUID? = nil, name: String, email: String) { self.id = id self.name = name self.email = email }}Now the migration to create the table:
struct CreateUser: Migration { func prepare(on database: Database) -> EventLoopFuture<Void> { database.schema("users") .id() .field("name", .string, .required) .field("email", .string, .required) .create() } func revert(on database: Database) -> EventLoopFuture<Void> { database.schema("users").delete() }}Register the migration in configure.swift:
app.migrations.add(CreateUser())1.3. CRUD Operations
Create:
let user = User(name: "Ivan", email: "ivan@example.com")try await user.save(on: database)Read:
let users = try await User.query(on: database).all()let user = try await User.find(id, on: database)Update:
guard let user = try await User.find(id, on: database) else { return }user.name = "New name"try await user.update(on: database)Delete:
guard let user = try await User.find(id, on: database) else { return }try await user.delete(on: database)Fluent automatically generates SQL queries, which greatly simplifies life for beginners.
2. MongoDB and Swift: The Flexibility of NoSQL
MongoDB is a document database where data is stored in BSON (binary JSON) format. For Swift, we use the MongoKitten library — a mature and actively supported