Persistence

The core package never assumes a storage layer. If you want SwiftData wired up for you, there's a separate product for that.

The default: you own storage

AdvancedKanban (the core product) has zero third-party dependencies and doesn't import SwiftData, Core Data, or anything else. KanbanBoard's onMove closure hands you a KanbanMove value — cardID, sourceColumnID, sourceIndex, destinationColumnID, destinationIndex — after the board has already applied the change to your in-memory columns binding. What you do with that value is entirely yours: write it to Core Data, send it to a server, log it, ignore it.

The optional adapter

AdvancedKanbanSwiftData is a second SPM product in the same package. It's never linked unless you explicitly add it — importing AdvancedKanban alone never pulls in SwiftData.

.package(url: "https://github.com/NerdSnipe-Inc/AdvancedKanban.git", from: "1.0.0")

// in your target's dependencies:
.product(name: "AdvancedKanban", package: "AdvancedKanban"),
.product(name: "AdvancedKanbanSwiftData", package: "AdvancedKanban"),  // optional

It ships two ready-made @Model types that already conform to the core protocols, plus a store that applies a move in one call:

TypeWhat it is
SwiftDataKanbanCard@Model, conforms to KanbanCard. id: UUID, title: String, sortIndex: Int.
SwiftDataKanbanColumn@Model, conforms to KanbanColumn. id: UUID, title: String, wipLimit: Int?, isCollapsed: Bool. cards is a computed property over its cascade-deleting relationship, sorted by sortIndex.
KanbanStoreWraps a ModelContext. apply(_ move: KanbanMove<UUID, UUID>) throws reassigns the moved card's column, renumbers every card in the destination column, and saves.

Wiring it up

import SwiftData
import AdvancedKanban
import AdvancedKanbanSwiftData

KanbanBoard(
    columns: $columns,
    onMove: { move in
        try? store.apply(move)   // store: KanbanStore, built from your ModelContext
    },
    // ...
)
Why onMove, not automatic persistence

The board mutates your local columns binding immediately, for a responsive UI, and calls onMove as a separate step. If you're using the SwiftData models directly, calling store.apply(_:) from onMove keeps every card's sortIndex correct on disk. Skipping that call still works for local, in-memory reordering, but the persisted order won't match what's on screen after your next fetch.

Bringing your own storage instead

Don't use SwiftData? Nothing above is required. Conform your Core Data entity, your GRDB record, or your plain server-backed struct to KanbanCard/KanbanColumn directly and apply KanbanMove however your storage layer expects — the same way the SwiftData adapter does, just without the ready-made types.