TursoSync 1.8.1
See the version list below for details.
dotnet add package TursoSync --version 1.8.1
NuGet\Install-Package TursoSync -Version 1.8.1
<PackageReference Include="TursoSync" Version="1.8.1" />
<PackageVersion Include="TursoSync" Version="1.8.1" />
<PackageReference Include="TursoSync" />
paket add TursoSync --version 1.8.1
#r "nuget: TursoSync, 1.8.1"
#:package TursoSync@1.8.1
#addin nuget:?package=TursoSync&version=1.8.1
#tool nuget:?package=TursoSync&version=1.8.1
TursoSync
The offline-sync + full-text-search layer for Turso on .NET.
It adds local↔cloud replication (push/pull/checkpoint against the Turso sync engine) and tantivy
full-text search — the pieces the official Turso.Data.Sqlite
binding doesn't ship. It carries a familiar ADO.NET surface (modeled on Turso.Data) so Dapper, DbUp and the
DbProviderFactory pattern work, but in its own Turso.Sync namespace so it coexists with the official
package rather than colliding with it.
Reach for the official Turso.Data.Sqlite for base local/remote access, the SQLite-compat facade, EF Core,
and NativeAOT. Reach for TursoSync when you need offline replication or FTS — the two are complementary.
using Turso.Sync;
// Local-only (offline fast path — plain engine, no sync overhead)
await using var conn = new TursoConnection("Data Source=app.db");
await conn.OpenAsync();
// …or synced against Turso Cloud
await using var synced = new TursoConnection(
"Data Source=app.db;Remote Url=libsql://my-db.turso.io;Auth Token=…");
await synced.OpenAsync();
synced.SyncDatabase!.Push(); // push local changes
synced.SyncDatabase!.Pull(); // pull + apply remote changes
Packages
| Package | What |
|---|---|
TursoSync |
The sync + FTS provider (namespace Turso.Sync): the sync engine (push/pull/checkpoint/stats), an ADO.NET surface (connection/command/reader/parameter/transaction, TursoFactory) to query synced databases, UDFs, aggregates, collations, load-extension, local at-rest encryption, connection pooling. |
TursoSync.DbUp |
DbUp database provider — DeployChanges.To.TursoDatabase(connectionString). |
TursoSync.Dapper |
Dapper type handlers that round-trip Ulid, DateTimeOffset and Guid as portable TEXT. |
dotnet add package TursoSync
dotnet add package TursoSync.DbUp # optional: migrations
dotnet add package TursoSync.Dapper # optional: Dapper type handlers
Highlights
- Two lanes, one API. No
Remote Url→ the plain local engine (AsyncIO=0, no IO pump); a remote (orSync=true) → the sync engine. In release builds, local performance is on par with SQLite. - Familiar surface, own namespace. Public types live in namespace
Turso.Sync(TursoConnection,TursoCommand, …), modeled onTurso.Dataso Dapper, DbUp and theDbProviderFactorypattern work — and namespaced so a project can reference both this and the officialTurso.Data.Sqlitewithout clashing. - Connection pooling on by default (
Pooling=falseto disable) — opening Turso is expensive, the pool makes the open-per-op pattern ~50× cheaper. - Extensibility:
CreateFunction/CreateAggregate/CreateCollation/EnableExtensions/LoadExtension. - Local at-rest encryption:
…;Encryption Cipher=aes256gcm;Encryption Key=<hex>. - Full-text search (tantivy):
…;Experimental Index Method=trueenablesCREATE INDEX … USING fts. Composes with encryption — the index lives inside the database file, so it's encrypted at rest too.
Connection string keys
Data Source (required) · Remote Url · Auth Token · Namespace · Bootstrap · Sync · Pooling
· Busy Timeout · Long Poll Timeout · Http Timeout · Push Operations Threshold · Encryption Cipher · Encryption Key
· Experimental Index Method.
Push batching
Pushes default to batches of 1,000 CDC operations, so a backlog accumulated offline can make progress
without uploading the entire change set in one request. Set Push Operations Threshold in the connection
string, or TursoSyncConfig.PushOperationsThreshold, to change the threshold. Zero explicitly restores
one request for the whole change set. A batch ends at a transaction boundary, so one larger transaction
can exceed the threshold. A retry resumes from the last batch the server acknowledged.
Connections to the same replica share one sync engine and must agree on the threshold. A conflicting
threshold is rejected when opening a connection. Close the existing connections and call
TursoConnection.ClearPool() before reopening with a different value.
Sync HTTP diagnostics
The opt-in HTTP diagnostics API requires TursoSync 1.8.0 or later (the next minor release; 1.7.x does not contain it). This change does not publish a package. Consumers such as Foxery must upgrade their TursoSync reference after that release is published.
Set TursoSyncConfig.HttpDiagnostics before TursoSyncDatabase.Create to include
bootstrap requests, or use TursoSyncDatabase.HttpDiagnostics on an open replica to
log a push:
var database = synced.SyncDatabase!;
var previous = database.HttpDiagnostics;
try
{
database.HttpDiagnostics = diagnostic => Console.WriteLine(diagnostic);
database.Push();
}
finally
{
database.HttpDiagnostics = previous;
}
The callback defaults to null (off). It receives one TursoSyncHttpDiagnostic when
an HTTP request finishes or fails: method, an allowlisted endpoint label (info,
pull-updates, push-updates, or other), request body bytes, time to response
headers, status, declared response bytes, actual bytes read, total duration, and
FailurePhase (None, BeforeHeaders, or ResponseBody). Unknown methods become
OTHER. No URL, query, arbitrary path, headers, credentials, payload, or exception
text is included. Null measurements mean unavailable; partial body bytes survive a
read failure. HTTP error statuses are reported unchanged and are not themselves
transport failures. Existing sync error handling and timeouts are unchanged.
Callbacks run synchronously under the sync operation lock; keep them fast and do not call back into the database. Callback exceptions are swallowed. Timings exclude the callback. Events arrive on completion, not while a request is stalled; an infinite HTTP timeout can therefore postpone an event indefinitely. The callback is shared by all connections using the same replica and captured per request: coordinate temporary changes with other database users if logging only one push.
Full-text search
Tantivy FTS is behind the engine's experimental index_method feature, so opt in with
Experimental Index Method=true (or TursoSyncConfig.ExperimentalIndexMethod). Without it,
USING fts fails to parse.
await using var conn = new TursoConnection(
"Data Source=app.db;Experimental Index Method=true");
await conn.OpenAsync();
conn.ExecuteNonQuery("CREATE INDEX idx_articles ON articles USING fts (title, body)");
// BM25-ranked search, with the matched terms highlighted.
using var cmd = conn.CreateCommand();
cmd.CommandText = """
SELECT id, fts_highlight(body, '<mark>', '</mark>', @q)
FROM articles
WHERE fts_match(title, body, @q)
ORDER BY fts_score(title, body, @q) DESC
""";
Tokenizers (default/raw/simple/whitespace/ngram) and per-column weights are set with
WITH (tokenizer = 'ngram', weights = 'title=2.0,body=1.0'). Automatic segment merging is disabled —
run OPTIMIZE INDEX <name> on a cadence (like VACUUM/ANALYZE) after bulk or continuous inserts.
Native library
The provider P/Invokes the turso_sync_sdk_kit native (the Turso sync engine + tantivy FTS). Released
packages carry it under runtimes/<rid>/native/. For local development against a self-built engine, point
TURSOSYNC_NATIVE_DIR at the folder containing the built turso_sync_sdk_kit library. Build the native in
release — debug builds are ~25× slower.
Engine version
The Turso engine (the turso_sync_sdk_kit native) is not vendored — CI builds it from
tursodatabase/turso at the commit pinned in
turso-engine.json, currently the stable v0.7.0 release. The pin keeps builds
reproducible and lets us validate each engine bump before adopting it.
- Bump it with
scripts/bump-turso.sh <tag|latest>(resolves the tag → commit SHA). - A weekly Engine bump workflow opens a PR when a newer release appears in the pinned series; CI builds
- tests against it on the PR, so an ABI change is caught in review before merge.
Examples
// Migrations (TursoSync.DbUp)
using DbUp;
var result = DeployChanges.To.TursoDatabase("Data Source=app.db")
.WithScriptsEmbeddedInAssembly(typeof(Program).Assembly)
.Build()
.PerformUpgrade();
// Dapper type handlers (TursoSync.Dapper)
Turso.TursoTypeHandlers.Register();
// A scalar UDF
conn.CreateFunction("times_two", 1, args => Convert.ToInt64(args[0]) * 2);
Status
TursoSync is the sync + FTS complement to the official Turso.Data.Sqlite
binding, not a replacement for it. Base local/remote access, the SQLite-compat facade, EF Core and NativeAOT
are official's domain — use that package directly for those. TursoSync owns the offline sync engine
(push/pull/checkpoint) and tantivy FTS, and carries just enough of an ADO.NET surface (modeled on Turso.Data,
see TURSO-PARITY.md) to query a synced database and support Dapper/DbUp. One known gap is
sync-lane at-rest encryption (base-lane encryption is supported).
Testing
rig test (or dotnet test) runs the unit suite. The live sync suites are gated on environment
variables and report Inconclusive (skip) when unset:
LiveSyncIntegrationTests— needsTURSOSYNC_TEST_SYNC_SERVERpointing at atursodbbinary; the harness starts atursodb --sync-serveron a free port per test.TursoSyncBehaviorTests— needsTURSOSYNC_TEST_REMOTE_URL(+TURSOSYNC_TEST_REMOTE_TOKEN) for a real Turso Cloud round-trip.
Copy .env.example to .env at the repo root and fill in what you have — the test project
loads it automatically. Real environment variables (and CI, which exports these) always take precedence.
Releasing
Releases are driven by shipRig (changesets) — config in .changeset/.
- Record intent:
shiprig add(pick the bump + summary; the three packages arefixed, so they version together;TursoSync.Testsis ignored). - Ship:
shiprig release→ versions + changelog → commit → tagsTursoSync@x.y.z→ push.
The pushed tag triggers the Release workflow, which builds all six RID natives (release + FTS,
stripped), packs, and publishes to NuGet via trusted publishing (OIDC — no API key). shipRig only
versions/tags/pushes; the cross-arch native build + publish stay in CI (.changeset/release.jsonc).
Never run shiprig publish here. It isn't in the pipeline, and .changeset/config.json names no package
source, so a local publish would pack on your machine, without the six native builds CI makes, and push that to
nuget.org. The only reason it doesn't today is that the version on disk is already published, so the push is
skipped as a duplicate. After a local shiprig version it would ship a broken package.
Day-to-day dev uses rig (.rig.json): rig build / rig test / rig coverage,
plus rig engine <tag|latest> (pin the engine) and rig pack (local Tier-0 pack + consume test).
License
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on TursoSync:
| Package | Downloads |
|---|---|
|
TursoSync.DbUp
A first-class DbUp database provider for Turso (DeployChanges.To.TursoDatabase(...)), running migrations through the TursoSync ADO.NET provider. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.9.1 | 0 | 11/1/2026 |
| 1.9.0 | 0 | 11/1/2026 |
| 1.8.1 | 61 | 10/31/2026 |
| 1.8.0 | 112 | 10/30/2026 |
| 1.7.0 | 53 | 10/30/2026 |
| 1.6.0 | 41 | 10/30/2026 |
| 1.5.0 | 286 | 10/28/2026 |
| 1.4.5 | 527 | 10/25/2026 |
| 1.4.4 | 154 | 10/25/2026 |
| 1.4.3 | 183 | 10/25/2026 |
| 1.4.2 | 156 | 10/24/2026 |
| 1.4.1 | 411 | 10/21/2026 |
| 1.4.0 | 3,571 | 8/9/2026 |
| 1.3.0 | 184 | 8/5/2026 |
| 1.2.0 | 150 | 8/3/2026 |
| 1.1.0 | 177 | 8/2/2026 |
| 1.0.1 | 224 | 7/16/2026 |
| 1.0.0 | 144 | 7/16/2026 |
| 0.1.0 | 173 | 6/18/2026 |
| 0.1.0-preview.1 | 318 | 6/17/2026 |