RediStack: Asynchronous Redis client for Swift (iOS/macOS)
RediStack is a modern, fully asynchronous client for Redis, written in Swift. It is built on top of the high-performance SwiftNIO framework, allowing efficient work with network requests without blocking the main thread. The library is ideal for iOS and macOS applications that require caching, queue management, or Pub/Sub.
RediStack supports all major Redis features: strings, hashes, lists, sets, transactions, pipelines, and publish/subscribe (Pub/Sub). The library is actively developed and maintained by the Swift community.
Installation
Add RediStack to your project via Swift Package Manager:
// Package.swiftdependencies: [ .package(url: "https://github.com/swift-server/RediStack.git", from: "1.0.0")],targets: [ .target(name: "MyApp", dependencies: ["RediStack"])]For CocoaPods use:
pod 'RediStack', '~> 1.0'Basic connection
Create a connection to a Redis server using RedisConnection:
import RediStackimport NIOCoreimport NIOPosix
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)let eventLoop = eventLoopGroup.next()
let connection = try await RedisConnection.connect( to: try .init(hostname: "localhost", port: 6379), on: eventLoop)Working with data
Examples of basic operations:
// Setting a valuetry await connection.set("user:1:name", to: "Alexey")try await connection.set("user:1:age", to: 30)
// Getting a valuelet name: String? = try await connection.get("user:1:name")print(name ?? "not found") // Output: Alexey
// Working with hashestry await connection.hset("user:1", field: "email", to: "alex@example.com")let email: String? = try await connection.hget("user:1", field: "email")
// Incrementlet newCount = try await connection.increment("page:views")print("Views: \\(newCount)")Transactions and pipelines
RediStack supports pipelines for sending multiple commands at once:
let pipeline = connection.pipeline()pipeline.set("key1", to: "value1")pipeline.set("key2", to: "value2")pipeline.get("key1")let results = try await pipeline.execute()// results — array of responses in command orderFor transactions use MULTI/EXEC:
try await connection.sendCommandsImmediately(false)try await connection.set("balance", to: 100)try await connection.decrement("balance")try await connection.sendCommandsImmediately(true)Pub/Sub (Publish and Subscribe)
RediStack supports asynchronous subscriptions to channels:
// Subscribe to a channellet subscriber = connection.subscribe(to: "updates") { event in switch event { case .message(let channel, let message): print("Received from \\(channel): \\(message)") default: break }}
// Publish a messagetry await connection.publish("Hello everyone!", to: "updates")Error handling and reconnection
For production applications, it is important to handle connection drops. RediStack provides reconnection mechanisms via RedisConnectionPool:
let pool = RedisConnectionPool( configuration: .init( initialServerConnectionAddresses: [.init(hostname: "localhost", port: 6379)], maximumConnectionCount: .maximum(5) ), eventLoopGroup: eventLoopGroup)
// Use pool like a regular connectiontry await pool.set("session:token", to: "abc123")Performance
Thanks to SwiftNIO, RediStack ensures non-blocking operation of all operations. This is especially important for iOS/mac