Akavache ships a V12 changelog on top of a 13.0.0 release and a wildcard install
An asynchronous, persistent key-value store for .NET desktop and mobile applications, backed by SQLite. Suited to both durable data such as user settings and cached data that expires, with optional encryption and System.Text.Json serialization.
At a glance
- What is it?
- Akavache is a SQLite backed key-value store for .NET desktop and mobile applications, split across ten NuGet packages with a serializer chosen as a generic type argument. Its overview documents the V12 backend rewrite in detail and says nothing about the 13.0.0 release that is already out, while the install snippet pins both packages to a floating version.
- Who is it for?
- Akavache is a reasonable cache for a ReactiveUI style application if you pick your packages once and pin them, because the design decisions are sound: native SQLite access without an ORM, one worker thread owning the handles, and a serializer fixed at compile time. Two things deserve a decision before you adopt it.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- reactiveui/Akavache2,550 ★ · +1
| Repository | 2026-10-01 | 2026-11-14 |
|---|---|---|
| reactiveui/Akavache | 2.5k | 2.6k |
1 Stars in the last 44 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The changelog documents V12 and the release list starts at 13.0.0
Three releases are visible: 13.0.0 on 2026-08-07, 12.1.1 on 2026-06-03 and 12.0.1-beta on 2026-04-19. The page's change section is titled for V12, and the upgrade instructions it links are titled as a migration from V11 to V12.
So the overview describes the second newest major version, not the newest. Nothing on the page says what 13.0.0 changed, and there is no V12 to V13 guide linked next to the V11 to V12 one, which is a conspicuous gap in a library whose storage layer is a SQLite file on the user's disk. A reader who upgrades by reading the page will arrive at a version whose changes are undocumented, in a project where the previous hop had a document of its own.
The repository itself is not neglected. The main branch was pushed on 2026-10-01, and the root carries a code of conduct, a contributing guide, a security policy, an editor config and a codecov configuration, so the work is happening; the page describing it has simply stopped at the previous major.
V12 dropped the ORM and put every native handle on one thread
The V12 notes describe a backend rewrite rather than a feature addition. The SQLite layer now talks to SQLitePCLRaw 3.x directly, and the sqlite-net-pcl ORM that used to sit in between was removed entirely.
Four consequences are named. Per-operation allocations go down, because prepared statements are cached and reused with parameters bound positionally instead of going through an object mapper. All native handle access is serialised onto a dedicated worker thread. Concurrent writes are coalesced at commit time rather than each producing its own transaction. And encrypted databases changed implementation, which is covered separately.
The worker thread is the part with a shape worth thinking about. Serialising every native handle access on one thread is what makes a cached statement pool safe to share, and it is also a single point through which every read and write passes. For a desktop or mobile cache, where the volumes are small and the latency budget is generous, that trade is easy. For anything else, the page gives no number, no benchmark and no queue depth, so the only way to reason about it is from the architecture.
Encryption moved from sqlcipher to SQLite3MultipleCiphers
One bullet in the V12 list is a swap of the encryption engine rather than a tuning change. Encrypted databases use SQLite3MultipleCiphers, abbreviated SQLite3MC, instead of sqlcipher.
That matters beyond the name, because SQLite3MC is a multipage encryption scheme with a different file layout, so a database file written by one of those engines is not interchangeable with a file written by the other. Nothing on the page discusses migration of an existing encrypted file, which is the one question a reader with an encrypted cache and an existing on disk file will have.
The package table lists encrypted SQLite persistence as its own package, Akavache.EncryptedSqlite3, sitting beside the plain Akavache.Sqlite3. That produces a second naming mismatch. The four cache types are named UserAccount, LocalMachine, Secure and InMemory, and Secure is described as encrypted storage for sensitive data such as credentials and API keys. The page never states which of the two SQLite packages backs Secure, so the mapping between the package names and the cache type names has to be discovered from the source or from the docs directory.
Four cache types, and one of them is an invitation to be deleted
The cache type list is the part of the API a user touches first, and it encodes a policy decision per bucket. UserAccount holds user settings and preferences that should persist and may sync. LocalMachine holds cached data that can be safely deleted by the system. Secure holds encrypted values. InMemory holds session data that does not survive a restart.
LocalMachine is the interesting one. Describing a cache as safe for the system to delete is not a storage detail, it is an instruction to the operating system's eviction logic, and it is the reason a build gets four databases instead of one.
The operations are uniform across them and all asynchronous. InsertObject writes a typed object, an optional expiry is passed as a DateTimeOffset computed at the call site, GetObject reads it back with a type argument, and GetOrFetchObject takes a key plus an asynchronous factory so a miss can be filled without a separate read and write. Credentials go through their own call, SaveLogin, which takes a user name, a password string and a third argument that the sample fills with a domain name.
The serializer is a generic argument, so it is fixed at compile time
A note above the initialization samples says WithAkavache, WithAkavacheCacheDatabase and Initialize always require an ISerializer to be defined as a generic type, with SystemJsonSerializer given as the example, and gives the reason: it ensures the cache instance is properly configured for serialization.
That single design choice explains the package table. There are four serializer packages: Akavache.SystemTextJson, described as recommended, Akavache.SystemTextJson.Bson for a BSON shaped payload, and Akavache.NewtonsoftJson. The V12 notes add that the pure JSON package no longer pulls in Newtonsoft.Json, which is why the split exists at all, plus JsonTypeInfo overloads for System.Text.Json so a project can register its own type metadata and stay trim safe under AOT.
So the choice of serializer is not a runtime setting you can flip per cache or per value. It is part of the type of the cache itself, which is a good fit for an application that picks one and lives with it, and a poor fit for a library that needs to read several formats.
The sample marks a call REQUIRED while the library still does it for you
The static initialization sample builds the cache through a Splat builder, and the first call inside it carries an inline comment reading REQUIRED with the words explicit provider initialization. An Important note above the samples then explains something less dramatic: WithSqliteDefaults will call WithSqliteProvider itself if it has not been called yet, for backward compatibility, but that automatic behaviour is deprecated and may be removed in a future version.
Two signals therefore point in opposite directions in the same section. The code says the call is mandatory. The note says the library already does it and will keep doing it for now. The stated reason for going explicit is forward compatibility with other dependency injection containers, which is a claim about the future rather than about the present.
The dependency injection sample, the one intended for containers rather than for static initialization, repeats the same pattern with the same inline comment, so at least the recommendation is consistent across both entry points.
The install snippet pins nothing, and one hop has a migration package
The first quick start step is two package references:
<PackageReference Include="Akavache.Sqlite3" Version="*" />
<PackageReference Include="Akavache.SystemTextJson" Version="*" />Both versions are wildcards. That is a placeholder for readers who just want it to compile, and it is a poor choice for anything else, because the library's storage layer changed substantially between major versions and one of those changes swapped the encryption engine underneath an existing database file.
The package table shows how the project itself has handled one such hop. A package named Akavache.V10toV11 exists specifically for V10 to V11 data migration. The next hop, V11 to V12, is handled by a document in the docs directory instead, linked from the change section, and no package appears for V12 to V13. So the migration story is three different mechanisms across three versions: a NuGet package, a markdown guide, and nothing at all.
The static initialization sample that follows the install step shows the shape a caller ends up with, a Splat builder chain that names the serializer, the provider and a database name in one expression.
Agent instruction files and a test file at the repository root
The root of the repository holds twenty entries, and a few of them do not belong to a library. There is AGENTS.md and there is CLAUDE.md, two instruction files aimed at coding agents, sitting next to the usual code of conduct, contributing guide and security policy. There is a file called test_null_url.cs at the top level, outside src/, outside any test project and outside the tools directory.
There are also two image directories, Images/ and assets/, with no statement anywhere on the page about which one is current, and a nuget.config plus a codecov.yml for package sources and coverage reporting.
The metadata is unusual in one more way. The project description says this is an asynchronous, persistent key-value store for desktop and mobile applications backed by SQLite, and the page's own title describes it as a store for native applications, while the repository's website field points at a session recording hosted on evolve.xamarin.com. So the link a visitor sees as this project's home is a conference talk, and the badge row leads to NuGet, coverage and a Slack workspace instead.
Editorial conclusion
Akavache is a reasonable cache for a ReactiveUI style application if you pick your packages once and pin them, because the design decisions are sound: native SQLite access without an ORM, one worker thread owning the handles, and a serializer fixed at compile time. Two things deserve a decision before you adopt it. The documentation you are reading describes V12 while 13.0.0 is already published, and the quick start installs with a floating version even though the on disk format has changed across major versions. Read the migration guide for the version you are actually jumping to, and pin the package version rather than copying the wildcard.
Frequently asked questions
What is Akavache and which NuGet packages does it need?
It is an asynchronous, persistent key-value store for .NET desktop and mobile applications built on SQLite3, under the MIT licence. The quick start installs two packages, Akavache.Sqlite3 and Akavache.SystemTextJson, and the package table lists ten in total, adding an encrypted SQLite package, a Newtonsoft.Json serializer, a BSON serializer, an HTTP downloader, a Drawing package, a Settings package and a V10 to V11 migration package.
Which SQLite encryption does Akavache use?
The V12 notes say encrypted databases use SQLite3MultipleCiphers, written as SQLite3MC, instead of sqlcipher. Encrypted SQLite persistence is shipped as its own package, Akavache.EncryptedSqlite3, separate from Akavache.Sqlite3, while the cache type list describes Secure as encrypted storage for credentials and API keys.
What cache types does Akavache expose?
Four. UserAccount holds user settings and preferences that should persist and may sync, LocalMachine holds cached data that can be safely deleted by the system, Secure holds encrypted values such as credentials and API keys, and InMemory holds data that does not survive an app session.
How do I upgrade Akavache from V11 to V12?
The page links a migration guide for that hop, docs/migration-v11-to-v12.md, and describes the V12 change behind it: the SQLite backend was rewritten for direct SQLitePCLRaw 3.x access, replacing the sqlite-net-pcl ORM layer. The earlier V10 to V11 hop is handled by a package instead, Akavache.V10toV11.
What changed in Akavache V12?
The SQLite backend was rewritten for direct SQLitePCLRaw 3.x access, replacing sqlite-net-pcl entirely, with cached prepared statements bound positionally, all native handle access serialised on a dedicated worker thread, and commit coalescing for concurrent writes. Settings properties became IObservable, disposal uses Interlocked patterns, and encryption moved to SQLite3MultipleCiphers.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/reactiveui-akavache)Star history chart for your README
[](https://hysenlabs.com/projects/reactiveui-akavache)Was this useful?