Introduction: Databases in the Swift Ecosystem
Swift has long moved beyond simple mobile app development. With the emergence of server-side frameworks such as Vapor and Perfect, the language has become a full-fledged tool for building backends. However, working with databases in Swift has its own specifics. Unlike Python or JavaScript, there are no built-in drivers here — everything is handled through third-party packages.
In this article, we will break down how to connect to two popular DBMS: the relational PostgreSQL and the document-oriented MongoDB. You will learn which libraries to use, how to configure the connection, and how to perform basic CRUD operations. The examples are aimed at iOS/macOS, but the code will also work in a server environment.
PostgreSQL in Swift: Classic Approach via Vapor and Fluent
Choosing a Library
For working with PostgreSQL in Swift, the de facto standard is Fluent — an ORM from the Vapor framework. Fluent supports PostgreSQL, MySQL, SQLite, and MongoDB (via a separate driver). If you need to work without Vapor, use PostgresClientKit — a low-level driver.
Connection Setup
Add the dependency to Package.swift:
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0")Basic configuration in configure.swift:
import Fluentimport FluentPostgresDriverimport Vapor
public func configure(_ app: Application) throws { app.databases.use(.postgres( hostname: "localhost", port: 5432, username: "swift_user", password: "secret", database: "swift_db" ), as: .psql) // Add migrations app.migrations.add(CreateUser())}CRUD Operations Using the User Model as an Example
Let's create a model and a migration:
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 }}
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() }}Example query in a controller:
// Create a userlet user = User(name: "Alexey", email: "alex@example.com")try await user.save(on: req.db)
// Find all userslet users = try await User.query(on: req.db).all()
// Filter by emaillet filtered = try await User.query(on: req.db) .filter(\\.$email == "alex@example.com") .first()Important: Fluent uses asynchrony via EventLoopFuture or async/await (starting from Vapor 4.60+). Make sure your environment supports Swift 5.5+.
MongoDB in Swift: Document Flexibility with MongoKitten
Choosing a Driver
For MongoDB, the main library is MongoKitten. It supports all modern versions of MongoDB, including Atlas (cloud version). An alternative is MongoSwift from MongoDB Inc., but MongoKitten is considered more "Swift-like" in style.
Connecting to the Database
Add to Package.swift:
.package(url: "https://github.com/OpenKitten/MongoKitten.git", from: "7.0.0")Connection example (for iOS/macOS):