An online backup copies an open database through database connections rather than copying its live files.
dotnet add package RecursiveAI.OneLiteRequires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.
Back up to a new, empty backup.db. The destination connection comes first in Backup.Create; an existing destination’s contents are replaced.
using RecursiveAI.OneLite; // Replace source.db with your existing database. using var input = Database.OpenReadOnly("source.db"); using var source = input.Connect(); using var output = Database.Open("backup.db"); using var target = output.Connect(); using var copy = Backup.Create(target, "main", source, "main"); while (copy.Step(8) != BackupStatus.Done) Thread.Sleep(25); Console.WriteLine("Backup complete");
Backup completeUnzip the example, then dotnet run.
The full program
The download creates source.db with a notes table and the text “Keep me”, backs it up to backup.db, then reopens the destination and reads the row. The snippet at the top accepts your existing database; the download supplies a small source.db for the demonstration. Backing up replaces the destination database’s contents; choose a separate output path. Busy and Locked are retried; other failures throw OneLiteException and roll back the destination.
using RecursiveAI.OneLite; using var sourceDb = Database.Open("source.db"); using var source = sourceDb.Connect(); using (var create = source.Prepare("CREATE TABLE IF NOT EXISTS notes(text);")) create.Step(); using (var insert = source.Prepare("INSERT INTO notes SELECT 'Keep me' WHERE NOT EXISTS (SELECT 1 FROM notes);")) insert.Step(); using (var destinationDb = Database.Open("backup.db")) using (var destination = destinationDb.Connect()) using (var backup = Backup.Create(destination, "main", source, "main")) { while (backup.Step(8) != BackupStatus.Done) Thread.Sleep(25); } using var savedDb = Database.OpenReadOnly("backup.db"); using var saved = savedDb.Connect(); using var query = saved.Prepare("SELECT text FROM notes"); while (query.Step()) Console.WriteLine(query.GetString(0));
Keep meVariations
For asynchronous page I/O, replace the loop in the snippet at the top with:
while (await copy.StepAsync(8) != BackupStatus.Done) await Task.Delay(25); Console.WriteLine("Backup complete");
Backup completeRelated recipes
The short answer
Use Backup.Create(destination, "main", source, "main"), then call Step until it returns Done. Dispose the backup and both connections. OneLite’s backup API copies database pages through its engine; it does not take an ordinary file copy of a database that may still be changing.
If you already use Microsoft.Data.Sqlite or EF Core, OneLite’s adapter implements the online backup API too (supported calls).
How do I back up a SQLite database in C#?
Open the source and destination as separate Database objects and create a connection from each. The destination comes first in Backup.Create. Reversing them replaces the wrong database, so keep the names explicit. The "main" strings name the schemas to copy, not paths. Paths belong to Database.Open.
The full example creates its own small source with CREATE TABLE IF NOT EXISTS notes(text) and inserts “Keep me” only if the table is empty. It then backs up the open connection. Reopening backup.db and selecting the text shows that the destination is readable, not just that a file exists. To use your own database, omit those setup statements and open your source path read-only, as in the snippet at the top.
Step(8) requests a batch of eight pages. That is a sample choice, not a required size. More means another step is needed. Busy and Locked are retry results rather than completion. The sample pauses between attempts. A service should also impose a deadline or cancellation policy so repeated contention cannot keep its job alive indefinitely.
Can I back up a SQLite database while it is open?
Yes. In OneLite, the source read transaction lasts for one backup step unless the source connection already has a transaction of its own. Other connections can read and write between steps. The destination’s write transaction stays open until completion or disposal; do not issue statements on its main database while the backup is unfinished.
A commit through another source connection or process causes the copy to restart on the next step. A commit through the source connection itself updates pages already copied without restarting. Progress therefore need not increase steadily. Remaining and PageCount describe the last step, and both start at zero before any step runs. These details are documented in OneLite’s backup API.
Is copying a SQLite database file a backup?
Use the online API for the open-database task here. SQLite’s own backup documentation describes the locks and failure risks involved in external file copying. A database API can coordinate the source read and destination transaction instead.
OneLite commits the replacement only at the final step. Disposing an unfinished backup leaves the destination’s old content unchanged. This does not make a backup an archive strategy by itself: choose a destination you retain and can restore from.
Back up to a new, empty destination file. OneLite requires matching page size and reserved bytes unless the destination has no pages and is not in WAL mode. A nonempty destination with a different page size can fail with SQLITE_READONLY. Encryption settings also affect reserved bytes; this plain-file example is not an encrypted-to-plaintext export. Use VACUUM INTO when the separate goal is a compacted copy rather than this incremental page-copy workflow.