A type-safe, Sendable-first DynamoDB layer for Swift with optimistic concurrency. DynamoDBTables makes it easy to use DynamoDB from Swift-based applications, with a particular focus on usage with polymorphic database tables — tables that don't have a single schema for all rows. It integrates with aws-sdk-swift by default and Soto by an opt-in package trait.
DynamoDBTables is a fork of smoke-dynamodb and acknowledges the authors of that original package.
- ✅ Strongly typed rows —
Codablemodels with automatic serialization - ✅ Optimistic concurrency — automatic row versioning and conditional writes
- ✅ Polymorphic tables — support single table designs - store and query heterogeneous item types
- ✅ Transactions — atomic multi-item writes with constraint support
- ✅ Retrying operations — automatic retry on concurrency conflicts
- ✅ Historical rows — append-only audit trails alongside mutable state
- ✅ TTL support — per-item time-to-live timestamps
- ✅ Testable — in-memory table implementations for unit testing
Full documentation is available on the Swift Package Index.
Add DynamoDBTables to your Package.swift. Choose the SDK integration that matches your project:
With aws-sdk-swift (default)
dependencies: [
.package(url: "https://github.com/swift-server-community/dynamo-db-tables", from: "0.1.0")
]
.target(
name: "MyApp",
dependencies: [
.product(name: "DynamoDBTablesAWS", package: "dynamo-db-tables")
]
)With Soto
dependencies: [
.package(url: "https://github.com/swift-server-community/dynamo-db-tables", traits: ["SOTOSDK"], from: "0.1.0")
]
.target(
name: "MyApp",
dependencies: [
.product(name: "DynamoDBTablesSoto", package: "dynamo-db-tables")
]
)import DynamoDBTables
struct Customer: Codable, Sendable {
let name: String
let email: String
}
// Insert
let key = StandardCompositePrimaryKey(partitionKey: "customer-123", sortKey: "profile")
let item = StandardTypedDatabaseItem.newItem(
withKey: key,
andValue: Customer(name: "Alice", email: "alice@example.com")
)
try await table.insertItem(item)
// Retrieve
if let retrieved: StandardTypedDatabaseItem<Customer> = try await table.getItem(forKey: key) {
print(retrieved.rowValue.name) // "Alice"
}The insertItem call above produces the following row in DynamoDB:
| PK | SK | CreateDate | RowType | RowVersion | LastUpdatedDate | Name | |
|---|---|---|---|---|---|---|---|
| customer-123 | profile | 2025-01-15T10:30:00Z | Customer | 1 | 2025-01-15T10:30:00Z | Alice | alice@example.com |
- PK and SK are the partition and sort key attributes, derived from the
StandardCompositePrimaryKeyyou provided. - CreateDate, RowType, RowVersion, and LastUpdatedDate are managed automatically by the library.
RowTyperecords which Swift type was stored so it can be decoded back correctly, andRowVersionenables optimistic concurrency — it starts at 1 and increments on each update. - Name and Email are your payload fields from the
Customerstruct, serialized by the library'sCodableencoding (attribute names are automatically capitalized).
This library is licensed under the Apache 2.0 License.