Skip to content

Moving from LiteDB: a guide, an API mapping and an import tool #297

Open

Description

@CaffeinatedCoder

From Discussion #14: @LeoYang06 suggested a comparison with LiteDB covering usage and design, and you replied that "we could provide a 'moving from LiteDb' section that could help developers in moving codebase, along with a migration tool from LiteDb". This issue scopes that for v6. It is part of #296 and fits the "desktop tools and internal apps on LiteDB" niche of #287.

Why now

LiteDB's last stable release is 5.0.21 (July 2024). 6.0 is in prerelease (6.0.0-prerelease.322 on NuGet, October 2026), and its release-readiness issue is still open. 6.x writes a new file format that 5.x cannot open; a writable open converts a 5.x file one way. Teams on LiteDB 5 are deciding now whether to move to 6.0 or elsewhere, and both paths start with "back up the file and migrate".

1. A guide: docs/moving-from-litedb.md

  • What stays familiar: an embedded, single-file, BSON document database with LINQ, indexes and transactions.
  • What is different, and why: async-only CRUD (since 4.0); source-generated mappers instead of BsonMapper reflection (AOT and trimming); DocumentDbContext with OnModelCreating instead of GetCollection<T>; DynamicCollection and BLQL (MQL-style JSON) instead of BsonExpression strings; field names stored lowercase; WAL sync modes (fix(wal): sync the WAL to disk before a commit is acknowledged #280) instead of LiteDB's commit model; multi-process WAL instead of Connection=Shared.
  • An API mapping table, one row per LiteDB construct, each marked equivalent, different shape, different semantics or no equivalent. A first cut:
LiteDB 5 BLite
new LiteDatabase(path) a DocumentDbContext subclass (typed) or new BLiteEngine(path) (schema-less) different shape
GetCollection<T>(name) a DocumentCollection<TId, T> property on the context equivalent
GetCollection(name) (BsonDocument) engine.GetOrCreateCollection(name, …) (DynamicCollection) equivalent
Insert, Update, Upsert, Delete, FindById InsertAsync, UpdateAsync, UpsertAsync, DeleteAsync, FindByIdAsync async only
Find(pred), FindOne(pred) AsQueryable().Where(pred)…ToListAsync(), FirstOrDefaultAsync(pred) equivalent
Query().Where().OrderBy().Limit() AsQueryable().Where().OrderBy().Take() equivalent
"$.Name = 'x'" (BsonExpression) BLQL { "name": "x" } different syntax
EnsureIndex(x => x.Name), unique HasIndex(x => x.Name, unique: true) in OnModelCreating equivalent
Index on $.Address.City HasIndex(x => x.Address.City) equivalent
[BsonId], [BsonField], [BsonIgnore] [Key], [Column], [NotMapped] equivalent
BeginTrans / Commit / Rollback BeginTransaction(), CommitAsync() / RollbackAsync(), or SaveChangesAsync() different shape
Rebuild() VacuumAsync(VacuumOptions) partial
Password= (AES) CryptoOptions (AES-256-GCM) different format; cannot open a LiteDB file
Connection=Shared AllowMultiProcessAccess (experimental, #288) different semantics
[BsonRef], DbRef, Include store the id and query again no equivalent
FileStorage (GetStorage<T>) the KV store holds byte arrays; no file streams no equivalent
Multi-key index on an array, expression index, collation, Int32/Int64 auto-increment ids, custom serializers (RegisterType) to verify
— CDC (Watch), TimeSeries, vector search, geo, audit sink, GDPR primitives, hot backup BLite only

2. An import tool

A command (a dotnet tool, or a small BLite.Import.LiteDb package — your call) that copies a LiteDB file into a BLite database:

  • Reads generically: every collection from GetCollectionNames() as BsonDocument, the index definitions from $indexes, and reports what it cannot copy (FileStorage chunks, DbRef links, expression indexes, collations) instead of dropping it silently.
  • Writes to DynamicCollections and re-creates the indexes it can, with a summary of what was skipped.
  • Documents larger than one page. DynamicCollection refuses a document over PageSize - 128 bytes (about 16 KB with the default pages) and cannot read one a typed collection wrote (The schema-less API cannot read a typed collection that holds a document larger than one page: FindAllAsync and BLiteMigration throw "Skipping type 69" #301). LiteDB documents can be much larger, so the import needs The schema-less API cannot read a typed collection that holds a document larger than one page: FindAllAsync and BLiteMigration throw "Skipping type 69" #301 fixed, or writes those documents another way and reports them.
  • Converts types through LiteDB's typed reader, never by copying raw bytes: Decimal, DateTime (LiteDB stores UTC and returns local time unless told otherwise; millisecond precision), Int32 vs Int64 kept as stored, ObjectId, Guid, binary, MinValue/MaxValue.
  • Never writes to the source. It opens the LiteDB file read-only, or works on a copy, because a writable open by LiteDB 6 converts a 5.x file one way. Encrypted sources take the password as input. A 4.x file needs LiteDB's own upgrade first; the tool says so instead of trying.
  • Shipping: pins the LiteDB package it reads with (5.0.21 for v8/v9 files), and states which file versions it accepts.

3. A test that proves the import

Questions

  • A dotnet tool, a package, or a command in Studio?
  • Should the import also write a typed context (generated entity classes), or stop at DynamicCollections?

Activity

  1. added this to the v6 milestone on Oct 17, 2026
  2. removed this from the v6 milestone on Oct 18, 2026
  3. mrdevrobot commented on Oct 18, 2026

    @mrdevrobot
    Contributor

    Kept, with a reduced scope: a "Moving from LiteDB" section in the documentation with an API mapping. The import tool is out of scope for now. The v6 milestone was self-assigned and has been removed; the maintainers will schedule this.

  4. LeoYang06 commented on Oct 20, 2026

    @LeoYang06

    Two notes on the import tool mentioned at the end (for future prioritisation)

    If this does get picked up again, my personal preference would be:

    • Packaging: since LiteDB is an embedded database, a lot of desktop and client applications end up with database files scattered across end users' local machines. When shipping a new version, developers typically need to migrate the user's existing database to the new one automatically, in code, at application startup. So if this gets built, a standalone, lightweight NuGet package — invoked from application code — would likely be more useful than a pure CLI tool, and a dotnet tool or a Studio feature could simply be a thin layer built on top of that package.
    • Scope: I'd argue that stopping at the data-level import (DynamicCollection) is sufficient — generating entity class code isn't necessary. Developers migrating an existing project already have their C# entity classes; all they really need is to swap out the attributes (e.g. [BsonId] → [Key]) and declare a DocumentDbContext. Reverse-engineering C# classes from schemaless BSON is more likely to introduce errors around nullable fields or type inference. The one thing worth guaranteeing is that the data and field-name conventions written by DynamicCollection can later be read back seamlessly by the user's own strongly-typed DocumentDbContext.

    Thanks again to the team for all the work you do for the community!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Projects

    • Status
      Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions