Skip to content
Back to skills

Postgres Nio

ASecurity

Expert guidance on using PostgreSQL with Swift. Use when developers mention: (1) PostgreSQL or Postgres in Swift, (2) postgres-nio library, (3) SQL queries in Swift, (4) PostgreSQL connection pooling, (5) prepared statements, (6) type-safe database access, (7) bulk loading or COPY FROM, (8) PostgresClient or PostgresConnection.

  • 11 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 10, 2026
databasesrustswiftsqlgitdatabaseperformance

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 10, 2026

npx -y skills add luokai0/ai-agent-skills-by-luo-kai --skill postgres-nio --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Postgres Nio?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Postgres Nio
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/luokai0-postgres-nio/badge)](https://www.skillsdirectory.com/skills/luokai0-postgres-nio)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
author: luo-kai
name: postgres-nio
description: 'Expert guidance on using PostgreSQL with Swift. Use when developers mention: (1) PostgreSQL or Postgres in Swift, (2) postgres-nio library, (3) SQL queries in Swift, (4) PostgreSQL connection pooling, (5) prepared statements, (6) type-safe database access, (7) bulk loading or COPY FROM, (8) PostgresClient or PostgresConnection.'
references:
  - postgres-patterns.md
---

# 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`:

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

### Basic Usage

```swift
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:

```swift
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!):

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

## Row Decoding

### Decode by Position

```swift
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

```swift
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

```swift
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:

```swift
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

```swift
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:

```swift
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

```swift
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

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

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

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

### Unix Domain Socket

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

## Error Handling

```swift
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:

```swift
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

Files in this skill

  • SKILL.md6.8 KB
  • references/postgres-patterns.md33.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.