postgres

The postgres-nio library provides a Swift PostgreSQL client with full async/await support, type-safe query building, connection pooling, and prepared statements.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "postgres" with this command: npx skills add joannis/claude-skills/joannis-claude-skills-postgres

PostgreSQL

The postgres-nio library provides a Swift PostgreSQL client with full async/await support, type-safe query building, connection pooling, and prepared statements.

Quick Start

Installation

Add to Package.swift :

dependencies: [ .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0") ]

Basic Usage

import PostgresNIO

// Using PostgresClient (recommended - includes connection pooling) let client = PostgresClient( configuration: .init( host: "localhost", port: 5432, username: "postgres", password: "secret", database: "myapp", tls: .disable ) )

// Run as a service try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { try await client.run() }

// Use client for queries
let rows = try await client.query("SELECT id, name FROM users")
for try await row in rows {
    let (id, name) = try row.decode((Int.self, String.self))
    print("User \(id): \(name)")
}

group.cancelAll()

}

Type-Safe Queries

Queries use string interpolation to prevent SQL injection:

let userId = 123 let email = "alice@example.com"

// Interpolated values become parameter bindings ($1, $2, ...) let query: PostgresQuery = "SELECT * FROM users WHERE id = (userId) AND email = (email)" // Generates: "SELECT * FROM users WHERE id = $1 AND email = $2" with bindings [123, "alice@example.com"]

let rows = try await client.query(query)

Dynamic Identifiers

Use unescaped for table/column names (not user input!):

let tableName = "users" // Must be trusted, not user input let query: PostgresQuery = "SELECT * FROM (unescaped: tableName) WHERE id = (userId)"

Row Decoding

Decode by Position

let rows = try await client.query("SELECT id, name, email, created_at FROM users") for try await row in rows { let (id, name, email, createdAt) = try row.decode((Int.self, String.self, String.self, Date.self)) }

Decode by Column Name

for try await row in rows { let id = try row["id"].decode(Int.self) let name = try row["name"].decode(String.self) let email = try row["email"].decode(String?.self) // Optional }

Custom Types

struct User: Decodable { let id: Int let name: String let email: String }

// Decode into custom type for try await row in rows { let user = try row.decode(User.self) }

Prepared Statements

Define reusable prepared statements for performance:

struct GetUserByEmail: PostgresPreparedStatement { typealias Row = (Int, String, Date)

static let sql = "SELECT id, name, created_at FROM users WHERE email = $1"

var email: String

func makeBindings() -> PostgresBindings {
    var bindings = PostgresBindings()
    bindings.append(email)
    return bindings
}

func decodeRow(_ row: PostgresRow) throws -> Row {
    try row.decode(Row.self)
}

}

// Execute prepared statement let results = try await connection.execute(GetUserByEmail(email: "alice@example.com")) for try await (id, name, createdAt) in results { print("Found user (id)") }

Transactions

try await client.withConnection { connection in try await connection.query("BEGIN")

do {
    try await connection.query("INSERT INTO accounts (id, balance) VALUES (\(fromId), \(fromBalance - amount))")
    try await connection.query("INSERT INTO accounts (id, balance) VALUES (\(toId), \(toBalance + amount))")
    try await connection.query("COMMIT")
} catch {
    try await connection.query("ROLLBACK")
    throw error
}

}

Bulk Loading (COPY FROM)

Efficiently load large datasets:

let rowCount = try await connection.copyFrom( table: "users", columns: ["name", "email", "created_at"], format: .csv(delimiter: ",", header: false) ) { writer in for user in users { var buffer = ByteBuffer() buffer.writeString("(user.name),(user.email),(user.createdAt)\n") try await writer.write(buffer) } } print("Inserted (rowCount) rows")

Connection Configuration

let config = PostgresClient.Configuration( host: "localhost", port: 5432, username: "postgres", password: "secret", database: "myapp", tls: .prefer(.makeClientConfiguration()), options: .init( minimumConnections: 2, maximumConnections: 10, connectionIdleTimeout: .minutes(5), keepAliveBehavior: .init(frequency: .seconds(30)) ) )

let client = PostgresClient(configuration: config)

TLS Options

// Disable TLS (local development) tls: .disable

// Prefer TLS (use if available) tls: .prefer(.makeClientConfiguration())

// Require TLS (production) tls: .require(.makeClientConfiguration())

Unix Domain Socket

let config = PostgresClient.Configuration( unixSocketPath: "/var/run/postgresql/.s.PGSQL.5432", username: "postgres", database: "myapp" )

Error Handling

do { let rows = try await client.query("SELECT * FROM users WHERE id = (id)") // ... } catch let error as PSQLError { switch error.code { case .uniqueViolation: throw MyError.duplicateEntry case .foreignKeyViolation: throw MyError.invalidReference default: throw error } }

Streaming Large Results

Results are streamed automatically with backpressure:

let rows = try await client.query("SELECT * FROM large_table")

// Process one row at a time - memory efficient for try await row in rows { let data = try row.decode(LargeData.self) try await processData(data) }

Supported Types

Swift Type PostgreSQL Type

Int , Int32 , Int64

integer , bigint

Float , Double

real , double precision

String

text , varchar

Bool

boolean

Date

timestamp , timestamptz

Data

bytea

UUID

uuid

[T]

array

JSON types json , jsonb

Reference Files

Load these files as needed for specific topics:

  • references/postgres-patterns.md
  • String interpolation for SQL safety, protocol hierarchy for encoding/decoding, variadic generics for row decoding, prepared statement patterns, hierarchical state machines, backpressure-aware row streaming, COPY FROM bulk loading, wire protocol encoding

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

swift-nio

No summary provided by upstream source.

Repository SourceNeeds Review
General

database-driver-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

hummingbird

No summary provided by upstream source.

Repository SourceNeeds Review
General

swift-concurrency

No summary provided by upstream source.

Repository SourceNeeds Review