Swift SDK

Add embedded PostgreSQL to an iOS or macOS app with Swift concurrency.

Use Oliphaunt from Swift or SwiftUI on iOS 17+ and macOS 14+. The package uses Swift 6 and includes the native runtime through Swift Package Manager.

Install

In Xcode, add https://github.com/f0rr0/oliphaunt.git as a package dependency and select version 0.8.0. Add the Oliphaunt product to your app target.

For a Swift package, add this dependency to Package.swift:

.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "0.8.0")

Then add .product(name: "Oliphaunt", package: "oliphaunt") to your target's dependencies. For a new iOS database, also download database-resources-0.2.2-swift.zip from the database resources release. Extract it, add the directory as a local Swift package, and link OliphauntSeedNativeIOSStandard to the app target. This supplies the initial empty database; it is required on iOS. macOS can initialize a new database without a seed.

For ICU collations, choose OliphauntSeedNativeIOSICU instead; it includes OliphauntICU. Keep ICU data linked when reopening an ICU database.

Run your first query

Call this function from an async context, such as a SwiftUI .task. It uses disposable storage and closes after reading a parameterized query result.

import Oliphaunt

func firstQuery() async throws {
    let db = try await OliphauntDatabase.open()
    do {
        let result = try await db.query(
            "SELECT $1::int4 AS answer",
            parameters: [.int32(42)]
        )
        let answer: Int32? = try result.rows[0].value(named: "answer")
        print(answer ?? 0) // 42
    } catch {
        try? await db.close()
        throw error
    }
    try await db.close()
}

Database work runs off the main actor. The database actor coordinates one PostgreSQL session; concurrent tasks do not create additional sessions.

Keep data between launches

Use this storage configuration instead of the disposable example above. Direct mode stays bound to its first root for the lifetime of the process; closing does not let the same process switch roots.

Use a file URL in your application's container:

import Foundation

let directory = try FileManager.default.url(
    for: .applicationSupportDirectory,
    in: .userDomainMask,
    appropriateFor: nil,
    create: true
).appending(path: "main.oliphaunt")

let db = try await OliphauntDatabase.open(
    configuration: OliphauntConfiguration(storage: .directory(directory))
)

Keep the handle in an application service. Reopen the same directory to access saved data. The default .temporaryDirectory is disposable.

Continue with the Swift guide, mobile lifecycle guide, or API reference.