---
title: "Back up a SQLite database in C#"
url: https://recursiveai.org/onelite/cookbook/backup-sqlite-database/
description: "Back up a SQLite database in C# with a runnable OneLite example, published NuGet packages and the actual console output."
version: "1.0.0"
---

# Back up a SQLite database in C#

**OneLite** is a free, open-source SQLite-compatible embedded SQL database for .NET from Recursive AI that reads and writes SQLite files. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneLite) · [GitHub](https://github.com/recursive-ai-oss/onelite-csharp) · [Docs](https://recursiveai.org/onelite/docs/) · [Download example (.zip)](https://recursiveai.org/onelite/cookbook/backup-sqlite-database/backup-sqlite-database.zip)

An online backup copies an open database through database connections rather than copying its live files.

```shell
dotnet add package RecursiveAI.OneLite
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (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.

```csharp
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");
```

```text
Backup complete
```

Unzip [the example](https://recursiveai.org/onelite/cookbook/backup-sqlite-database/backup-sqlite-database.zip), 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.

```csharp
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));
```

```text
Keep me
```

## Variations

For asynchronous page I/O, replace the loop in the snippet at the top with:

```csharp
while (await copy.StepAsync(8) != BackupStatus.Done)
    await Task.Delay(25);
Console.WriteLine("Backup complete");
```

```text
Backup complete
```

## Related recipes

- [Open an existing SQLite file](https://recursiveai.org/onelite/cookbook/open-existing-sqlite-database-csharp/)
- [Shrink a SQLite file](https://recursiveai.org/onelite/cookbook/shrink-sqlite-file-incremental-vacuum-csharp/)

## 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](https://recursiveai.org/onelite/cookbook/microsoft-data-sqlite-ef-core-without-native-library/) implements the online backup API too ([supported calls](https://recursiveai.org/onelite/docs/adapter/#what-is-supported)).

## 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](https://recursiveai.org/onelite/docs/backup-blob/).

## Is copying a SQLite database file a backup?

Use the online API for the open-database task here. SQLite’s own [backup documentation](https://www.sqlite.org/backup.html) 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.
