English | 简体中文
JsonData is a data persistence framework designed for the Swift cross-platform ecosystem. It offers a mental model and API that are fully consistent with Apple's SwiftData, but under the hood it is powered by the battle-tested GRDB, and it supports Linux and Windows.
Whether you need heavy concurrent queries on the server side or a responsive UI on cross-platform clients, JsonData delivers a SwiftData-like, silky-smooth development experience.
About the name: Why such an odd name, "JsonData"? Check the git commit history — this library originally persisted data using JSON files. The performance turned out to be too poor, so it switched to GRDB, but the name... well, changing it would ripple through everything, so it stuck.
- Falls back to SwiftData by default: on macOS and iOS,
import JsonDatais equivalent toimport SwiftData; on other platforms it automatically switches to the GRDB-backed JsonData implementation. - SwiftData API parity:
@Model,ModelContext, andModelContainermatch SwiftData; the View-side@Queryis provided by the UI layer (SwiftUI / SwiftTUI), while the explicitcontext:variant lives in the standalone productJsonData_Query. - GRDB: The underlying engine is SQLite, which is essentially the same backend SwiftData uses.
Add the following dependency to your project's Package.swift:
dependencies: [
.package(url: "https://github.com/zxss702/JsonData.git", branch: "main")
]Add the desired product to the corresponding target's dependencies:
targets: [
.target(
name: "YourApp",
dependencies: [
"JsonData", // SwiftData on Apple platforms; JsonDataCore elsewhere. To force GRDB on Apple, depend on JsonDataCore instead.
// "JsonData_Query", // Only needed when you require the explicit-context @Query (non-SwiftUI/SwiftTUI)
]
)
]Use the @Model macro exactly as you would with SwiftData — no tedious database schema statements required:
import JsonData // This is the only difference!!
@Model
public final class TodoItem {
@Attribute(.unique) public var id: UUID
public var title: String
public var isCompleted: Bool
public var createdAt: Date
public init(title: String) {
self.id = UUID()
self.title = title
self.isCompleted = false
self.createdAt = Date()
}
}Initialize your data container at app launch (or at the SwiftUI entry point):
I highly recommend using a global variable.
// Create an in-memory database (for testing) or a persistent SQLite database
let container = try ModelContainer(for: TodoItem.self)
let context = ModelContext(container)Type-safe Predicate query mechanism:
// Insert new data
let newItem = TodoItem(title: "Learn JsonData")
context.insert(newItem)
try? context.save()
// Query data
let descriptor = FetchDescriptor<TodoItem>(
predicate: #Predicate { $0.isCompleted == false }, // Mostly the same, but not as comprehensive as Foundation's Predicate used by SwiftData; JsonDataCore's Predicate is a self-contained reimplementation.
sortBy: [SortDescriptor(\.createdAt, order: .reverse)]
)
let pendingTodos = try context.fetch(descriptor)The persistence core (JsonData / JsonDataCore) does not ship with the View-side @Query, matching Apple's layering: @Query lives in the UI integration layer.
| Scenario | Import | @Query |
|---|---|---|
| Persistence only | import JsonData |
None |
| SwiftUI (Apple) | import SwiftUI + import JsonData |
System _SwiftData_SwiftUI environment-injected version |
| SwiftTUI | import SwiftTUI |
SwiftTUI's environment-injected version (re-exports JsonData) |
| No UI / explicit context | import JsonData + import JsonData_Query |
init(filter:sort:context:) |
SwiftUI example:
import SwiftUI
import JsonData
struct TodoListView: View {
@Environment(\.modelContext) private var context
@Query(sort: [SortDescriptor(\.createdAt)])
var todos: [TodoItem]
var body: some View {
List(todos) { todo in
Text(todo.title)
}
}
}Non-UI (explicit context) requires the extra JsonData_Query dependency:
// Package.swift
dependencies: [
.product(name: "JsonData", package: "JsonData"),
.product(name: "JsonData_Query", package: "JsonData"),
]
// Source
import JsonData
import JsonData_Query
struct Worker {
@Query(sort: [SortDescriptor(\.createdAt)], context: ModelContext.shared)
var todos: [TodoItem]
}Do not use JsonData_Query together with SwiftTUI/SwiftUI's @Query in the same file, or the modules will collide.
We welcome your code contributions and suggestions! Before submitting, please read our Contributing Guide (CONTRIBUTING.md).
This project is licensed under MPL-2.0 (Mozilla Public License 2.0).
This means:
- You are free to use this framework in your commercial, closed-source projects (no need to open-source your App).
- But if you directly modify this framework's source code, you must open-source those modifications back to the community under MPL-2.0. We encourage everyone to help make JsonData better together!