LiteDB vs SQLite: Choosing the Right Embedded Database for .NET

Getting Started with LiteDB — Installation, Basics, and ExamplesLiteDB is a lightweight, fast, embedded NoSQL database for .NET applications. It stores documents in BSON (Binary JSON) format, supports ACID transactions, and runs in-process without a separate server. This makes it ideal for desktop apps, small services, mobile apps using Xamarin/.NET MAUI, and any scenario that needs a simple, zero-configuration, file-based data store.


Why choose LiteDB?

  • Embedded and serverless: the database runs inside your application process and stores data in a single .db file.
  • No external dependencies: add the NuGet package and you’re ready.
  • Document-oriented: store flexible, schema-less documents (POCOs) with fast BSON serialization.
  • ACID transactions: safe writes with journal/locking support.
  • Indexes and LINQ support: create indexes on fields and query using LINQ or LiteDB’s query API.
  • Small footprint: minimal memory and disk overhead.

Installation

You can install LiteDB via NuGet. For .NET CLI:

dotnet add package LiteDB 

Or via Package Manager Console:

Install-Package LiteDB 

For .NET 6/7/8/9 projects the same package works; ensure your project targets a supported runtime. If you use LiteDB v5 or v6 features, check the package version and migration notes.


Basic concepts

  • Database: represented by a single file (e.g., data.db).
  • Collection: like a table — a set of documents of the same kind.
  • Document: a BSON object; you can map C# POCOs directly.
  • BsonDocument: LiteDB’s raw document representation (similar to a dictionary).
  • Id: each document has an _id field (default type is ObjectId or BsonValue types).
  • Index: supports single-field and compound indexes for faster queries.

Opening a database and CRUD with POCOs

Here’s a concise example using a simple POCO class:

using LiteDB; using System; using System.Collections.Generic; public class Person {     public int Id { get; set; }        // LiteDB will treat 'Id' as the document id     public string Name { get; set; }     public int Age { get; set; }     public List<string> Tags { get; set; } } class Program {     static void Main()     {         // Open (or create) a database file         using var db = new LiteDatabase(@"MyData.db");         // Get (or create) a collection named "people"         var col = db.GetCollection<Person>("people");         // Create indexes         col.EnsureIndex(x => x.Name);         col.EnsureIndex(x => x.Age);         // Insert a document         var person = new Person { Name = "Alice", Age = 30, Tags = new List<string>{"admin","team"} };         col.Insert(person); // Id is set automatically if int and 0         // Read documents         var results = col.Find(x => x.Age > 20);         foreach (var p in results)         {             Console.WriteLine($"{p.Id}: {p.Name} ({p.Age})");         }         // Update         person.Age = 31;         col.Update(person);         // Delete         col.Delete(person.Id);     } } 

Notes:

  • LiteDB maps property named “Id” or “_id” as the document identifier by convention. You can use other types like ObjectId or Guid.
  • For thread safety, use a single LiteDatabase instance per file and share it across threads. LiteDB manages concurrency internally.

Working with BsonDocument (dynamic use)

If you prefer a schema-less approach or want to manipulate documents dynamically:

using(var db = new LiteDatabase("MyData.db")) {     var col = db.GetCollection("products");     var doc = new BsonDocument     {         ["name"] = "Widget",         ["price"] = 9.99,         ["stock"] = 100     };     col.Insert(doc);     var res = col.FindOne(Query.EQ("name", "Widget"));     Console.WriteLine(res["price"]); } 

BsonDocument gives full control over document structure and types.


Queries and indexes

LiteDB supports LINQ and its own query API. Use indexes to speed up queries:

var col = db.GetCollection<Person>("people"); // LINQ var adults = col.Find(p => p.Age >= 18 && p.Name.StartsWith("A")); // Query API var q = Query.And(Query.GTE("Age", 18), Query.StartsWith("Name", "A")); var adults2 = col.Find(q); 

To create compound indexes, use string paths or expressions:

col.EnsureIndex("Tags[]");      // index array items col.EnsureIndex(x => x.Name);   // expression-based 

File storage (File Storage API)

LiteDB has a file storage system (like GridFS) to store binary files inside the same .db file:

using var db = new LiteDatabase("MyData.db"); var fs = db.FileStorage; // Upload a file using var fsIn = File.OpenRead("photo.jpg"); fs.Upload("photo.jpg", fsIn); // Download using var fsOut = File.Create("downloaded.jpg"); fs.Download("photo.jpg", fsOut); // List files foreach (var file in fs.Find(Query.All())) {     Console.WriteLine($"{file.Id} - {file.Filename}"); } 

Files are stored in a special collection and can have metadata.


Transactions and concurrency

LiteDB supports ACID transactions. When using the default settings, write operations are transactional. For multi-threaded apps, reuse the same LiteDatabase instance. If you need multiple processes accessing the same file, LiteDB supports shared access with a lock file, but performance characteristics differ—embedded databases are primarily designed for single-process access.


Backup and Compact

  • Backup: copy the .db file while the database is closed, or use the built-in Backup API to export safely.
  • Compact: to reduce file size after many deletions, use the Shrink/Checkpoint/Export methods depending on LiteDB version. Example:
db.Rebuild(); // compacts and rebuilds file (method name varies by version) 

Check the version docs for exact API names (Rebuild, Shrink, or Compact).


Migrations and schema versioning

Since LiteDB is schema-less, adding new fields to POCOs is straightforward. For structural changes (renaming fields, transforming data), write a small migration routine:

var col = db.GetCollection<Person>("people"); foreach(var doc in col.FindAll()) {     // e.g., rename field "FullName" to "Name"     if(doc["FullName"] != null)     {         doc["Name"] = doc["FullName"];         doc.Remove("FullName");         col.Update(doc);     } } 

Run migrations once at startup when upgrading application versions.


Examples & patterns

  • Offline-first apps: store data locally in LiteDB and sync with a server when online. Keep a queue collection for pending changes, track timestamps and GUIDs for conflict resolution.
  • Settings store: use a small collection for app settings (one document per namespace).
  • Caching layer: cache API responses in LiteDB to survive restarts.
  • Local logs: append-only collection for local audit logs (compact periodically).

Example: simple sync queue pattern

public class SyncItem {     public int Id { get; set; }     public string Entity { get; set; }     public string Operation { get; set; } // Create/Update/Delete     public BsonDocument Data { get; set; }     public DateTime QueuedAt { get; set; } } 

Push SyncItem entries to the queue collection and process them on connectivity.


Tips & best practices

  • Reuse a single LiteDatabase instance per file to maximize performance and thread-safety.
  • Create indexes on fields you query frequently.
  • Prefer typed POCO collections when possible for clarity and compile-time safety.
  • Use BsonDocument for flexible, dynamic data but be mindful of type handling.
  • Periodically compact the database if you perform many deletions or large file operations.
  • Keep backups before running destructive migrations.

Troubleshooting common issues

  • Locked file errors: ensure only one process writes or use proper shutdown. Check for lingering handles in other processes.
  • Unexpected nulls/missing fields: schema-less nature means older documents may lack new fields—use safe access patterns.
  • Large file growth: perform compaction/Rebuild after many deletes or large file uploads.

Resources

  • Official LiteDB documentation and GitHub repository for API references, version-specific migration guides, and examples.

LiteDB is a practical choice when you need an easy-to-embed, fast, document database for .NET with minimal configuration. The examples above should get you started with installation, basic CRUD, file storage, and common patterns like offline sync.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *