Offline first
The app writes to its own database, whether SwiftData, SQLite or Room. The SDK tracks every change and syncs as soon as the network is back.

tightrelay is the sync service for native apps. Your app keeps its local database. tightrelay delivers the changes to every device and resolves conflicts on the server.
Take Windows offline and edit there, then edit on the Mac and reconnect Windows. The later change wins, everywhere.
The service has no app-specific tables. It stores JSON documents, versions them and distributes changes. A schema is optional, and it is configuration, not server code.
The app writes to its own database, whether SwiftData, SQLite or Room. The SDK tracks every change and syncs as soon as the network is back.
The key lives in the Secure Enclave, TPM or Android Keystore. New devices find their account via iCloud Keychain or Block Store; others pair by QR.
Shared spaces for teams or businesses, with invites by QR code and roles to manage, edit or read.
Every change carries a hybrid logical clock timestamp. Per document, the later change wins, and every device ends up in the same state.
If you want, tightrelay only syncs with an active subscription. The server verifies purchases, renewals, expiry and refunds itself. When a subscription lapses, sync pauses and the data stays.
Collections appear with the first sync. Add a schema whenever you like: in the console form, suggested from your data, or from your code. After that, only changes that don’t break older app versions pass.
No server to set up, no tables to create, no schema to write. All you need is an app ID and the SDK.
Pick an app ID in the console. No API key, no password: every device signs itself up on its first sync.
Get it via Swift Package, NuGet or Maven. A small adapter connects it to the database your app already has.
create(collection: "notes", …) and sync(). The collection appears with the first sync, on every device.
Later, if you want, a schema: in the console form, suggested from the stored data, or from your code with tightrelay-cli schema push, in CI too.
Swift, C# and Kotlin, with no third-party dependencies. All three run the same test vectors and behave the same.
let client = TightRelayClient( configuration: .init(baseURL: api, appId: "stundennachweis", clientSchema: 1, deviceName: "Mac"), store: MySwiftDataStore(), identities: KeychainIdentityStore(appId: "stundennachweis"), recovery: ICloudKeychainRecoveryStore(appId: "stundennachweis")) try await client.create(collection: "clients", data: ["name": "Miller Ltd"]) try await client.update(id, set: ["archived": true]) // merge try await client.delete(id) // tombstone let report = try await client.sync() // push, then pull
var client = new TightRelayClient( new TightRelayConfiguration(api, "stundennachweis", ClientSchema: 1, DeviceName: Environment.MachineName), store: new MySqliteStore(db), identities: new FileIdentityStore(identityPath), // key in the TPM recovery: new DpapiRecoveryStore(recoveryPath)); await client.CreateAsync("clients", new JsonObject { ["name"] = "Miller Ltd" }); await client.UpdateAsync(id, new JsonObject { ["archived"] = true }); await client.DeleteAsync(id); var report = await client.SyncAsync();
val client = TightRelayAndroid.client( context, api, appId = "stundennachweis", clientSchema = 1, store = MyRoomStore(db)) // key in the Keystore client.create("clients", jsonOf("name" to "Miller Ltd")) client.update(id, jsonOf("archived" to true)) client.delete(id) val report = client.sync() // also from WorkManager
Each round is a push and a pull over HTTPS. Every request is signed with the device key.
The app saves as usual. The SDK stamps the change with the device clock and queues it for upload.
The server validates the schema if there is one, compares timestamps and only accepts newer data. If the change is older, the device gets the current version back.
Every accepted change gets the next number in its space, without gaps, even with concurrent uploads.
The device fetches everything after its last number, page by page, one transaction each. If the connection drops, nothing is lost.
A small scope keeps the service easy to understand and predictable. If your app needs one of these, tightrelay isn’t the right fit today.
No real-time pushDevices sync after changes, at launch and every few minutes. Too slow for chat, plenty for work data.
No field-level mergingWhen two devices change the same document, the later change wins as a whole.
No filesPhotos and PDFs don’t belong in the sync. A document is at most 64 KB.
No web clientBuilt for native apps with their own database, not for browsers.
The time tracker for freelancers syncs clients, projects and entries through tightrelay. A running timer shows up on the other devices right away.
Start a timer on two devices at once and a rule on the server stops the older one. Rules like this run in the same transaction as the upload.
Sign up in the console. Once your account is approved, create your app and add the SDK. Collections appear with the first sync.