<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Stacklyn Labs Blog]]></title><description><![CDATA[aPractical Flutter engineering from Stacklyn Labs: offline-first architecture, local databases (hive_ce, Isar, drift), App Store and Google Play releases, and l]]></description><link>https://stacklynlabs.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 12:48:02 GMT</lastBuildDate><atom:link href="https://stacklynlabs.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Isar Alternative for Flutter: Community, Plus or Drift?]]></title><description><![CDATA[We tested isar_community, isar_plus and drift against a real Isar 3 file and checked Android 16 KB alignment.]]></description><link>https://stacklynlabs.hashnode.dev/isar-alternatives-flutter</link><guid isPermaLink="true">https://stacklynlabs.hashnode.dev/isar-alternatives-flutter</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[Databases]]></category><category><![CDATA[Android]]></category><category><![CDATA[Mobile Development]]></category><dc:creator><![CDATA[Stacklyn Labs]]></dc:creator><pubDate>Fri, 06 Nov 2026 02:15:59 GMT</pubDate><content:encoded><![CDATA[<p><em>Originally published on <a href="https://stacklynlabs.com/blog/isar-alternatives-flutter/">Stacklyn Labs</a>.</em></p>
<p>Your Flutter app keeps its data in <code>isar</code> 3.1.0+1. It builds, it ships, and your users' data opens every morning. But the last stable Isar release on pub.dev is from April 25, 2023, the 4.0 line has sat at a dev prerelease since August 2023, and Google Play has set a date after which app updates must support 16 KB memory pages. So you look for an Isar alternative for Flutter and find three names: <code>isar_community</code>, <code>isar_plus</code> and <code>drift</code>.</p>
<p>The pages that rank for this explain how to use Isar or list alternatives in a sentence each. None opens a real Isar 3 file with each successor or checks the Android binaries. We did both. The short version: the original Android libraries are not 16 KB aligned, <code>isar_community</code> is the cheap fix, <code>isar_plus</code> is a different database with a familiar API, and drift means leaving the Isar family on purpose.</p>
<p>If you are picking a database from scratch rather than replacing one, start with <a href="https://stacklynlabs.com/blog/building-zero-latency-mobile-apps-hive-vs-isar-vs-sqlite-choosing-a-flutter-local-database-in-2026/">picking a Flutter local database for an offline-first app</a>. This post is only about getting off original Isar.</p>
<p>A note on the evidence: our tests ran in a scratch pure-Dart project on Dart 3.12.0, on Windows, not in a Flutter app on a device. The data was written by <code>isar</code> 3.1.0+1: two collections, a unique index with <code>replace: true</code>, an <code>@enumerated</code> enum, a <code>DateTime</code>, a <code>double</code>, an embedded list, an <code>IsarLink</code> and a <code>@Backlink</code>. The 16 KB result comes from reading the published Android binaries, not from running on a 16 KB device. Versions are from pub.dev on October 13, 2026. Anything not marked as tested comes from docs and changelogs.</p>
<h2>Which Isar alternative for Flutter fits your project</h2>
<table>
<thead>
<tr>
<th>Where you are</th>
<th>Pick</th>
<th>What it costs you</th>
</tr>
</thead>
<tbody><tr>
<td>Shipped app on <code>isar</code> 3.1.0+1, Android updates must keep shipping</td>
<td><code>isar_community</code> 3.3.2</td>
<td>Package and import swap, a regenerate, and a newer code generator toolchain</td>
</tr>
<tr>
<td>Shipped app, planning a long life</td>
<td><code>isar_community</code> now, <code>drift</code> later</td>
<td>A full data-layer rewrite, on your schedule instead of Google's</td>
</tr>
<tr>
<td>Shipped app that now needs web, encryption or string ids</td>
<td><code>isar_community</code> now, then a copy migration to <code>isar_plus</code></td>
<td>Model changes for the v4 API and a copy step you write and test yourself</td>
</tr>
<tr>
<td>New app, wants Isar's object API, needs web or encryption</td>
<td><code>isar_plus</code> 1.3.9</td>
<td>One maintainer, docs that lag the code, no async APIs or watchers on web</td>
</tr>
<tr>
<td>New app with relational data or a long horizon</td>
<td><code>drift</code> 2.35.2</td>
<td>SQL schema and migrations from day one, no Isar code reused</td>
</tr>
</tbody></table>
<h2>Why staying on isar 3.1.0+1 now has a deadline</h2>
<p>Original Isar has stalled. It is not marked discontinued on pub.dev. The last stable release, 3.1.0+1, came out on April 25, 2023, and the newest prerelease, 4.0.0-dev.14, on August 21, 2023. The last repository commit, on June 14, 2025, added a privacy manifest.</p>
<p>Stalled is not broken. <code>isar</code> 3.1.0+1 declares an SDK constraint below Dart 3.0, yet it still resolves and runs on Dart 3.12 (tested). The cost is your toolchain: <code>isar_generator</code> 3.1.0+1 pinned our project to analyzer 5.13.0, source_gen 1.5.0 and build_runner 2.4.13. Every other generator in the app, such as <code>freezed</code>, <code>json_serializable</code> or <code>riverpod_generator</code>, has to fit under that ceiling.</p>
<p>That was a preference problem until Android's page size change turned it into a deadline. We read the ELF <code>PT_LOAD</code> alignment (<code>p_align</code>) of the published Android libraries:</p>
<table>
<thead>
<tr>
<th>Binary</th>
<th>arm64-v8a</th>
<th>x86_64</th>
</tr>
</thead>
<tbody><tr>
<td><code>isar_flutter_libs</code> 3.1.0+1, <code>libisar.so</code></td>
<td>0x1000 (4 KB), not 16 KB aligned</td>
<td>0x1000, not 16 KB aligned</td>
</tr>
<tr>
<td><code>isar_community_flutter_libs</code> 3.3.2, <code>libisar.so</code></td>
<td>0x4000 (16 KB)</td>
<td>0x4000 (16 KB)</td>
</tr>
<tr>
<td><code>isar_plus</code> 1.3.9 release, <code>libisar_plus_android_arm64.so</code></td>
<td>0x4000 (16 KB)</td>
<td>not checked</td>
</tr>
</tbody></table>
<p>Google's <a href="https://developer.android.com/guide/practices/page-sizes">page size guidance</a> says apps targeting Android 15 (API level 35) and higher must support 16 KB memory pages on 64-bit devices on Google Play. It also says that starting February 1, 2027, app updates that do not support 16 KB pages cannot be released.</p>
<p>If your app targets API 35 and still bundles the original <code>libisar.so</code>, the clock is real, and upstream has not published a new build of that binary since 2023. To check your own build, <code>readelf -l</code> on each <code>.so</code> prints an <code>Align</code> value on every <code>LOAD</code> line. Our check shows how the library is built, not how the app behaves on a 16 KB device, so test on one before release.</p>
<h2>isar_community: the same database, rebuilt for 2026</h2>
<p><code>isar_community</code> is the Isar v3 code under a new name. Its README describes a fork "focusing primarily on bug fixes and small updates for version 3." The changelog since the rename is maintenance: libmdbx 0.13.8, 16 KB page support (from 3.2.0-dev.1), an Android namespace, a Linux GLIBC 2.36 fix, dependency bumps. It runs on Android, iOS, Linux, macOS and Windows, with no web support and no built-in encryption, because v3 never had either.</p>
<h3>The swap</h3>
<pre><code class="language-yaml">dependencies:
  isar_community: ^3.3.2                # was isar
  isar_community_flutter_libs: ^3.3.2   # was isar_flutter_libs

dev_dependencies:
  isar_community_generator: ^3.3.2      # was isar_generator
  build_runner: any                     # resolved 2.15.1 for us
</code></pre>
<p>The package name changes, the library name does not:</p>
<pre><code class="language-dart">// before
import 'package:isar/isar.dart';

// after
import 'package:isar_community/isar.dart';
</code></pre>
<h3>You must regenerate before it compiles (tested)</h3>
<p>We tried the lazy route first: swap the packages, keep the old <code>.g.dart</code> files. They fail to compile with a const assertion on <code>Isar.version</code>:</p>
<pre><code class="language-text">Outdated generated code. Please re-run code generation using the latest generator.
</code></pre>
<p>After <code>dart run build_runner build</code>, the new <code>.g.dart</code> differed from the old one in one place: the embedded version string changed from <code>'3.1.0+1'</code> to <code>'3.3.2'</code>. Every record in our v3 file read back identical, including the link, the backlink count, the embedded list and the enum. New writes worked. No data migration step was needed.</p>
<p>The real change is the toolchain: ours moved to analyzer 10.2.0, source_gen 4.2.4 and build_runner 2.15.1. That lifts the analyzer 5 ceiling off your other generators, and also means they all upgrade at once. The runtime package still says Dart 2.17, but <code>isar_community_generator</code> 3.3.2 needs Dart 3.9, so that is your real floor.</p>
<h3>Rollback worked, once</h3>
<p>We reopened the file that <code>isar_community</code> had written to (four records by then) with the original <code>isar</code> 3.1.0+1. All four came back. That is one test on one schema, not a guarantee, so keep backups of real user files anyway.</p>
<p>We made this same swap in a shipping app. <a href="https://stacklynlabs.com/product/rent-folio/">Rent Folio, our offline landlord app template</a>, was built on <code>isar</code> 3.1.0, with the 4 KB aligned Android binaries from the table above. It now runs on <code>isar_community</code>, using the steps in this section: swap the three packages, change the imports, regenerate the <code>.g.dart</code> files, then check that existing data reads back.</p>
<p>We did not test whether <code>isar_flutter_libs</code> and <code>isar_community_flutter_libs</code> can sit in one Flutter app, which happens if another dependency still pulls in <code>isar</code>. Run <code>flutter pub deps</code> and look for a stray <code>isar</code> before you find out on a device. If the same app keeps settings or a cache in Hive, that store has its own version of this problem, and <a href="https://stacklynlabs.com/blog/migrate-hive-to-hive-ce/">the Hive CE migration path</a> covers what breaks there.</p>
<h2>isar_plus: Isar v4 with one maintainer</h2>
<p><code>isar_plus</code> is not a newer v3. Its 1.0.0 changelog says it is based on the Isar v4 architecture, the line Isar's own README still marks as not ready for production. On top of v4 it adds web support (SQLite compiled to WASM, with an IndexedDB fallback), encryption through SQLCipher (SQLite engine only), string ids, an optional SQLite engine and <code>dynamic</code> or <code>Map</code> properties. The code generator ships inside the package. It needs Dart 3.7, Flutter 3.24 and Android minSdk 23.</p>
<p>The API is different enough that you will touch every data access:</p>
<table>
<thead>
<tr>
<th>Isar v3</th>
<th>isar_plus</th>
</tr>
</thead>
<tbody><tr>
<td><code>writeTxn(...)</code></td>
<td><code>writeAsync(...)</code></td>
</tr>
<tr>
<td><code>writeTxnSync(...)</code></td>
<td><code>write(...)</code> (operations are sync by default)</td>
</tr>
<tr>
<td><code>txn(...)</code></td>
<td><code>readAsync(...)</code></td>
</tr>
<tr>
<td><code>Id? id = Isar.autoIncrement</code></td>
<td>non-nullable <code>int id</code>, set with <code>collection.autoIncrement()</code></td>
</tr>
<tr>
<td><code>@enumerated</code></td>
<td><code>@enumValue</code></td>
</tr>
<tr>
<td><code>IsarLink</code>, <code>IsarLinks</code>, <code>@Backlink</code></td>
<td>removed: use embedded objects or your own id fields</td>
</tr>
<tr>
<td><code>replace: true</code> on unique indexes</td>
<td>removed: the latest write always wins</td>
</tr>
</tbody></table>
<p>On web, its limitations page says async APIs and watchers are not supported, everything runs on the main thread, and most environments fall back to IndexedDB.</p>
<p>The docs already lag the code. The README tells you to call <code>Isar.initializeIsarCore(download: true)</code> in unit tests. That method does not exist in 1.3.9; we had to use <code>Isar.initialize([library])</code>, which does not download anything. The limitations page still mentions lazy-loaded links, which v4 removed.</p>
<h3>It cannot open your v3 file, and the attempt changes it (tested)</h3>
<p>Opening our v3 file with <code>isar_plus</code> 1.3.9 failed with:</p>
<pre><code class="language-text">DatabaseError: IsarError: Schema error: Could not deserialize existing schema.
</code></pre>
<p>The <a href="https://github.com/ahmtydn/isar_plus/blob/main/docs/isar-plus-docs/content/docs/recipes/migrate_from_isar3.mdx">isar_plus migration guide</a> quotes a <code>VersionError</code> instead, so do not search your logs for that one.</p>
<p>The failed open was not harmless. <code>shop.isar</code> grew from 1 MB to 20 MB and its bytes no longer matched the backup. Our data survived: both <code>isar</code> 3.1.0+1 and <code>isar_community</code> 3.3.2 still read all three records. Do not count on that. Back up first, and never point <code>isar_plus</code> at the v3 directory and name.</p>
<h3>The documented side-by-side setup does not resolve (tested)</h3>
<p>The guide's plan is sound: keep the old packages next to <code>isar_plus</code>, copy every record across, delete the old ones. But its pubspec, with <code>isar</code>, <code>isar_flutter_libs</code> and <code>isar_generator</code> 3.1.0+1 beside <code>isar_plus</code>, fails <code>dart pub get</code>. <code>isar_generator</code> wants source_gen <code>^1.2.2</code>, <code>isar_plus</code> wants <code>^4.2.3</code>. Swapping in <code>isar_community_generator</code> 3.3.2 fails too, on analyzer <code>&gt;=8 &lt;11</code> against <code>&gt;=12.1 &lt;14</code>.</p>
<p>The runtimes alone do resolve together. What worked for us:</p>
<ol>
<li>Generate the legacy <code>.g.dart</code> with the old generator first.</li>
<li>Commit it.</li>
<li>Remove the legacy generator, keeping only the legacy runtime.</li>
</ol>
<h3>The guide's build command deletes the file you kept (tested)</h3>
<p>The guide then tells you to run:</p>
<pre><code class="language-bash">dart run build_runner build --delete-conflicting-outputs
</code></pre>
<p>That flag deleted our hand-kept <code>legacy_model.g.dart</code>, and the build failed. Excluding the legacy model in <code>build.yaml</code> fixed it:</p>
<pre><code class="language-yaml">targets:
  $default:
    builders:
      isar_plus:isar_generator:
        generate_for:
          exclude: [lib/legacy_model.dart]
      source_gen:combining_builder:
        generate_for:
          exclude: [lib/legacy_model.dart]
</code></pre>
<h3>The copy itself worked (tested)</h3>
<p>With both packages imported under aliases, the legacy runtime and <code>isar_plus</code> loaded in one Dart process, each with its own native library:</p>
<pre><code class="language-dart">import 'package:isar_community/isar.dart' as legacy;
import 'package:isar_plus/isar_plus.dart' as plus;
</code></pre>
<p>We copied all three records into a new <code>shop_plus</code> instance in the same directory. The <code>IsarLink</code> became an <code>int? categoryId</code> and the enum was mapped by name. Afterwards, <code>collection.autoIncrement()</code> returned 4, so new ids continue past the copied ones. The legacy file was untouched at 1 MB.</p>
<p>So the isar_plus route is a v4 model rewrite, a pubspec the guide gets wrong, a build that deletes your legacy file, and a copy step you must test against real user data. Leaving for drift needs the same copy step plus a rewrite of every query. On an app of any real size, either one is weeks of work before a user sees anything new, and we cannot tell you how many for yours. If what you need is a working offline app rather than a storage project, <a href="https://stacklynlabs.com/products/?cat=mobile-applications">our offline-first Flutter app source code</a> has that layer already built and running without a server.</p>
<h2>drift: leaving the Isar family on purpose</h2>
<p>Drift is a different kind of database. It is a typed layer over SQLite with its own query builder, stream-based watched queries and schema migrations, and it runs on all six Flutter platforms, web included. Nothing from your Isar code carries over: collections become tables, links become foreign keys, watchers become watched queries, and your users' data needs a one-time copy on first launch. We did not test a drift migration, because it is a rewrite by design.</p>
<p>What you get for that is the healthiest maintenance picture of the three. Drift 2.35.2 was published on October 7, 2026, and the repository had commits on October 11. Its lead maintainer has 3,739 commits, and several other people contribute regularly. One thing to know before you start: there is no drift 3.x on pub.dev yet, but the repository already has commits migrating parts of the project to drift3. A major version is in progress, so plan for one more upgrade on drift's side at some point.</p>
<p>Choose drift when you are rewriting anyway or starting fresh. As a way to beat the February 2027 deadline on a shipped app, it is the slowest of the three.</p>
<h2>A fork is a liability you inherit</h2>
<p>Isar itself is the lesson. It was a well-liked database built largely by one author, with 885 commits in the repository and none in its recent history. When those releases stopped, every app built on it inherited the problem. Choosing a fork does not remove that risk. It moves it to someone else, usually one person, and makes you depend on them staying interested.</p>
<p>Look at who is behind each option today:</p>
<table>
<thead>
<tr>
<th></th>
<th>Maintainers</th>
<th>Repository (GitHub, October 13, 2026)</th>
<th>Promise</th>
</tr>
</thead>
<tbody><tr>
<td><code>isar_community</code></td>
<td>One main maintainer doing nearly all recent merges; an outside memory-leak fix landed in July 2026</td>
<td>193 stars, 51 open issues, last commit September 8, 2026</td>
<td>Bug fixes and small updates for v3</td>
</tr>
<tr>
<td><code>isar_plus</code></td>
<td>One person, with no other human contributor in the top list</td>
<td>73 stars, 5 open issues, last commit August 4, 2026</td>
<td>A v4-based engine with web, encryption and an SQLite option</td>
</tr>
<tr>
<td><code>drift</code></td>
<td>Long-running lead maintainer plus regular contributors</td>
<td>3,290 stars, 211 open issues, last commit October 11, 2026</td>
<td>Ongoing, with a major version in progress</td>
</tr>
</tbody></table>
<p>A fourth fork, <code>isar_db</code>, also shows up in search: two releases, the latest 1.0.1+1 from October 2025. We did not test it.</p>
<p>None of this says either fork is bad. <code>isar_community</code> did exactly what it promised and shipped 16 KB binaries the original never got. But when you adopt a fork, plan as if you may one day be its maintainer:</p>
<ul>
<li>Pin exact versions rather than carets, so an upgrade is always a decision.</li>
<li>Keep a tested export of every collection to plain JSON or SQL. If the fork stalls, leaving becomes a data copy instead of an archaeology project.</li>
<li>Watch the repository's commits and issues as well as its pub.dev page.</li>
<li>Write down which native binary ships in your app, and check its alignment again whenever Android's requirements move.</li>
</ul>
<h2>Pre-migration checklist</h2>
<ol>
<li>Copy real <code>.isar</code> files off a test device and keep them out of the app directory.</li>
<li>Check <code>p_align</code> on every <code>.so</code> in your release APK, not only Isar's.</li>
<li>Run <code>flutter pub deps</code> and look for any package that still pulls in <code>isar</code>.</li>
<li>Confirm Dart 3.9 or later for <code>isar_community_generator</code>, or Dart 3.7, Flutter 3.24 and minSdk 23 for <code>isar_plus</code>.</li>
<li>List your other code generators and check they accept the new analyzer range.</li>
<li>Regenerate every <code>.g.dart</code>; never edit the version string by hand.</li>
<li>Open the copied files with the new build and compare every collection.</li>
<li>For <code>isar_plus</code>, give the new database its own name, and exclude legacy models in <code>build.yaml</code> before running <code>build_runner</code>.</li>
<li>Keep one release where you could still roll back before deleting the old data.</li>
</ol>
<h2>Where to go from here</h2>
<p>If you would rather not spend your next sprint on this, <a href="https://stacklynlabs.com/hire-us/?service=mobile_app">we can plan and run your Flutter app's database migration</a> for you. And since neither <code>isar_community</code> nor the original v3 encrypts data at rest, read <a href="https://stacklynlabs.com/blog/securing-local-first-applications-a-flutter-architecture-study/">where to keep encryption keys in a local-first Flutter app</a> before you decide how much protection your stored data needs.</p>
<h2>References</h2>
<ul>
<li><a href="https://pub.dev/packages/isar">isar</a>, <a href="https://pub.dev/packages/isar_community">isar_community</a>, <a href="https://pub.dev/packages/isar_plus">isar_plus</a> and <a href="https://pub.dev/packages/drift">drift</a> on pub.dev</li>
<li><a href="https://github.com/isar-community/isar-community">isar_community repository</a> and its <a href="https://pub.dev/packages/isar_community/changelog">changelog</a></li>
<li><a href="https://github.com/ahmtydn/isar_plus">isar_plus repository</a>, <a href="https://pub.dev/packages/isar_plus/changelog">changelog</a> and <a href="https://github.com/ahmtydn/isar_plus/blob/main/docs/isar-plus-docs/content/docs/recipes/migrate_from_isar3.mdx">migration guide from Isar 3</a></li>
<li><a href="https://github.com/simolus3/drift">drift repository</a></li>
<li><a href="https://github.com/isar/isar">Original Isar repository</a></li>
<li><a href="https://developer.android.com/guide/practices/page-sizes">Android developers: support 16 KB page sizes</a></li>
</ul>
<hr />
<p><em>Further reading: <a href="https://stacklynlabs.com/blog/migrate-hive-to-hive-ce/">Migrate Hive to hive_ce: what breaks after the pubspec swap</a></em></p>
]]></content:encoded></item><item><title><![CDATA[Migrate Hive to hive_ce: What Breaks After the Pubspec Swap]]></title><description><![CDATA[Tested on real Hive 2 box files: typeId 200/201 clashes, transitive hive packages, the one-way typeId door and generator upgrades.]]></description><link>https://stacklynlabs.hashnode.dev/migrate-hive-to-hive-ce</link><guid isPermaLink="true">https://stacklynlabs.hashnode.dev/migrate-hive-to-hive-ce</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[hive]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[Databases]]></category><dc:creator><![CDATA[Stacklyn Labs]]></dc:creator><pubDate>Thu, 05 Nov 2026 04:59:17 GMT</pubDate><content:encoded><![CDATA[<p><em>Originally published on <a href="https://stacklynlabs.com/blog/migrate-hive-to-hive-ce/">Stacklyn Labs</a>.</em></p>
<p>Your Flutter app runs on <code>hive</code> 2.2.3. It still opens its boxes and still ships. But <code>flutter pub upgrade</code> keeps stalling on <code>hive_generator</code>, and the last stable <code>hive</code> release on pub.dev is from June 2022. Meanwhile <code>hive_ce</code>, the community continuation of Hive v2, has overtaken the original: 1,317,184 downloads in the last 30 days against 1,131,007 for <code>hive</code> when we checked on October 12, 2026.</p>
<p>So you look up how to migrate Hive to hive_ce. The official page covers swapping the packages and the imports, and calls hive_ce a drop-in replacement for Hive v2. That is true as far as it goes. It does not say whether your users' existing box files still open, what happens when another package in your tree still depends on <code>hive</code>, or that one hive_ce feature removes your ability to roll back.</p>
<p>We ran the migration against real Hive 2 data to find out. This hive_ce migration guide covers the swap in one short section and spends the rest on what the docs leave out. If you are still deciding whether hive_ce is the right home at all, start with <a href="https://stacklynlabs.com/blog/building-zero-latency-mobile-apps-hive-vs-isar-vs-sqlite-choosing-a-flutter-local-database-in-2026/">how hive_ce compares with Isar, drift and SQLite in 2026</a>.</p>
<p>A note on the evidence: our tests ran in a scratch pure-Dart project on Dart 3.12.0, on Windows, not in a Flutter app on a device. Anything below about <code>initFlutter</code> comes from the hive_ce source, changelogs and issue tracker.</p>
<h2>The swap the docs already cover</h2>
<p>Three package names change in <code>pubspec.yaml</code>. These are the current versions on pub.dev as of October 12, 2026:</p>
<pre><code class="language-yaml">dependencies:
  hive_ce: ^2.20.2          # was hive
  hive_ce_flutter: ^2.4.0   # was hive_flutter

dev_dependencies:
  hive_ce_generator: ^1.11.3  # was hive_generator
  # keep your existing build_runner entry
</code></pre>
<p>Then every import changes:</p>
<pre><code class="language-dart">// before
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

// after
import 'package:hive_ce/hive_ce.dart';
import 'package:hive_ce_flutter/hive_ce_flutter.dart';
</code></pre>
<p>The import change is not optional. With <code>hive</code> removed and the old imports left in place, the analyzer stops at <code>uri_does_not_exist</code> on <code>package:hive/hive.dart</code>.</p>
<p>Three small traps sit inside those few lines:</p>
<ul>
<li><strong>The generator is on 1.x, not 2.x.</strong> <a href="https://github.com/IO-Design-Team/hive_ce/issues/62">Issue #62</a> is a user who copied hive_ce's version number into <code>hive_ce_generator: ^2.8.0+3</code> and got a version-solving failure.</li>
<li><strong>The SDK floor is Dart 3.4.</strong> The README's getting-started snippet shows <code>sdk: ^3.0.0</code>, but all three packages declare <code>^3.4.0</code> on pub.dev.</li>
<li><strong>hive_ce_flutter 2.4.0 needs Flutter 3.44.0 or later.</strong> On an older Flutter, <code>^2.4.0</code> will not resolve. Use <code>hive_ce_flutter: ^2.3.4</code> instead: the 2.3.x line needs Flutter 3.27.0 or later, and the same constraint still picks up 2.4.0 once you upgrade Flutter.</li>
</ul>
<h2>Your existing box files open unchanged</h2>
<p>The migration page says Hive v4 data is not compatible. It never says outright that Hive 2 files are.</p>
<p>We tested it. With <code>hive</code> 2.2.3 and <code>hive_generator</code> 2.0.1 we wrote four boxes: a typed box of <code>Product extends HiveObject</code> (with <code>String</code>, <code>double</code>, enum, <code>DateTime</code> and <code>List&lt;String&gt;</code> fields, under both an auto-increment key and a string key), an untyped box holding a mixed map, a <code>LazyBox</code>, and an AES-encrypted box.</p>
<p>We saved what Hive 2 read back as a baseline, then opened the same files under <code>hive_ce</code> 2.20.2 in three states: after only the pubspec and import swap, after regenerating adapters with <code>hive_ce_generator</code>, and after a full move to <code>GenerateAdapters</code>. In all three, every value, every key and every <code>HiveObject.key</code> matched the baseline, including the lazy and encrypted boxes. No data migration step was needed.</p>
<p>The limits: one model, one platform, not your schema on an Android phone. Before you ship, copy a real production box off a test device and open it with the new build.</p>
<h2>Check typeIds 200 and 201 before you upgrade a Flutter app</h2>
<p>This is the biggest gap in the official guide, and it only affects Flutter apps.</p>
<p>Since <code>hive_ce_flutter</code> 2.0.0, a release its changelog marks as breaking, <code>Hive.initFlutter()</code> registers a <code>ColorAdapter</code> at typeId 200 and a <code>TimeOfDayAdapter</code> at typeId 201 for you. If one of your models already uses 200 or 201, your own registration throws <code>There is already a TypeAdapter for typeId 200</code>. That is <a href="https://github.com/IO-Design-Team/hive_ce/issues/105">issue #105</a>, filed by a developer migrating from the original packages. In <a href="https://github.com/IO-Design-Team/hive_ce/issues/291">issue #291</a>, closed February 2026, the complaint was that the reserved IDs were undocumented.</p>
<p>Run this before you touch the pubspec:</p>
<pre><code class="language-bash">grep -rnE "typeId *[:=] *20[01]\b" lib/
</code></pre>
<p>It catches both <code>@HiveType(typeId: 200)</code> annotations and hand-written adapters with <code>final int typeId = 201;</code>.</p>
<p>If you get a hit, do not renumber your model. Changing a typeId orphans every record already stored under it. Move the Flutter adapters instead: since <code>hive_ce_flutter</code> 2.3.0 their IDs are configurable. In the current source, <code>initFlutter</code> takes them as optional positional parameters:</p>
<pre><code class="language-dart">Future&lt;void&gt; initFlutter([
  String? dir,
  HiveStorageBackendPreference backendPreference =
      HiveStorageBackendPreference.native,
  int? colorAdapterTypeId,      // default 200
  int? timeOfDayAdapterTypeId,  // default 201
  bool useMaterialUi = false,
])
</code></pre>
<p>Pick two IDs no model of yours uses. If you stored <code>Color</code> values through the old ecosystem's adapter, read <a href="https://github.com/IO-Design-Team/hive_ce/issues/182">issue #182</a> first: that format is not compatible, and a bug reading legacy colour data was only fixed in <code>hive_ce_flutter</code> 2.3.2.</p>
<h2>Find any package that still pulls in <code>hive</code></h2>
<p>Your pubspec can be clean while your dependency tree is not. Two common sources of the original package:</p>
<ul>
<li><code>hydrated_bloc</code> 9.1.5 and older depend on <code>hive ^2.0.0</code>. It moved to <code>hive_ce</code> in 10.0.0, released January 2025.</li>
<li><code>hive_flutter</code> 1.1.0 depends on <code>hive</code>, so a forgotten <code>hive_flutter</code> line brings it back.</li>
</ul>
<p>Find them with this (use <code>dart pub deps</code> for a pure Dart package):</p>
<pre><code class="language-bash">flutter pub deps | grep -E "\bhive(_flutter|_generator)? [0-9]"
</code></pre>
<p>Anything it prints is the original package, not the CE one.</p>
<h3>What two copies of Hive do</h3>
<p>We reproduced this with both packages installed. They run as two separate engines: <code>identical(ce.Hive, old.Hive)</code> returns <code>false</code>, and each has its own adapter registry and open boxes.</p>
<p>Opening the same box from both failed. On Windows the error was:</p>
<pre><code class="language-text">PathAccessException: lock failed, path = 'data_both\shared.lock'
</code></pre>
<p>That wording is Windows only; other platforms word it differently. Either way it looks like a package that cannot open its box, not like two copies of Hive.</p>
<h3>The override shim</h3>
<p>The best fix is upgrading the offending package. If you cannot, the hive_ce repository ships a stand-in <code>hive</code> package under <code>overrides/hive</code> for exactly this case. This is the <code>dependency_overrides</code> entry from the <a href="https://docs.hive.isar.community/migrations/transitive_hive_dependencies.md">Hive CE docs on transitive Hive dependencies</a>, which we used as is:</p>
<pre><code class="language-yaml">dependency_overrides:
  hive:
    git:
      url: https://github.com/IO-Design-Team/hive_ce
      ref: 18f92b53295e9eb77ebd4830d905a72cd404a126
      path: overrides/hive
</code></pre>
<p>Pub resolved <code>hive 0.0.0 from git ... (overridden)</code>. After that, <code>identical()</code> returned <code>true</code>, and a write through one import was visible through the other: one engine, one box.</p>
<p>The costs: every machine that resolves dependencies, CI included, needs git and access to GitHub. You are pinned to one commit, so check the docs for a newer <code>ref</code> when you upgrade. And you still list <code>hive_ce</code> as a direct dependency. Treat the shim as a bridge until the other package moves.</p>
<h2>The one-way door: typeIds above 223</h2>
<p>Rolling back works up to a point: data <code>hive_ce</code> wrote with the same model and plain types read back correctly in <code>hive</code> 2.2.3.</p>
<p>The point is typeId 224. Original Hive caps custom typeIds at 223, and <code>hive_ce</code> 2.10.0 raised the limit to 65439. Once you register an adapter above 223 and write with it, the original package can no longer read that box. We tested typeId 300 in <code>hive</code> 2.2.3 and got two different failures:</p>
<ul>
<li>registering the adapter: <code>HiveError: TypeId 300 not allowed.</code></li>
<li>opening the box without it: <code>HiveError: Cannot read, unknown typeId: 21. Did you forget to register an adapter?</code></li>
</ul>
<p>The 21 is not your ID. It appears to be the marker hive_ce writes for an extended typeId; that is what we observed, not something the docs state.</p>
<p>So keep a rollback window. Ship the plain migration first, let it run in production for a release or two, and only then allow typeIds above 223.</p>
<h2>What changes in your adapters and toolchain</h2>
<p>Your old generated <code>.g.dart</code> files compile against <code>hive_ce</code> as they are, so regeneration can wait if you want a smaller first diff. When you do run <code>dart run build_runner build</code>, three things change:</p>
<table>
<thead>
<tr>
<th>Old <code>hive_generator</code> output</th>
<th><code>hive_ce_generator</code> output</th>
<th>Effect</th>
</tr>
</thead>
<tbody><tr>
<td><code>final int typeId = 0;</code></td>
<td><code>final typeId = 0;</code></td>
<td>None</td>
</tr>
<tr>
<td><code>break;</code> in enum adapter cases</td>
<td>removed</td>
<td>None</td>
</tr>
<tr>
<td><code>fields[1] as double</code></td>
<td><code>(fields[1] as num).toDouble()</code></td>
<td>A stored int no longer crashes a double field</td>
</tr>
</tbody></table>
<p>The bigger change is what the old generator was holding back. In a fresh Dart 3.12 project, adding <code>hive_generator</code> 2.0.1 resolved <code>analyzer</code> 6.4.1, <code>source_gen</code> 1.5.0 and <code>build_runner</code> 2.4.13, and downgraded <code>test</code> and other packages. After switching to <code>hive_ce_generator</code>, the same project resolved <code>analyzer</code> 14.5.0, <code>source_gen</code> 4.3.0 and <code>build_runner</code> 2.16.2. If your app also uses <code>freezed</code>, <code>json_serializable</code> or any other generator, <code>hive_generator</code> was probably the anchor keeping them all old. We infer that from the version constraints; we have not seen an issue that states it. It is still the best reason to migrate that is not about maintenance.</p>
<p>If you're on Isar instead, the original <code>isar_generator</code> holds your toolchain back in the same way, and its Android binaries add a deadline of their own. We tested <a href="https://stacklynlabs.com/blog/isar-alternatives-flutter/">the Isar alternatives for Flutter against a real Isar 3 file</a>.</p>
<p>Add it up and the three-line migration is really a typeId audit, a dependency tree review, a decision about a git override, a regeneration, and a read-back test against real user data. On an app you wrote yourself, plan for a careful day. On a codebase you inherited, budget longer, because first you have to learn where every box is opened. If what you need is a working offline app rather than a storage migration project, <a href="https://stacklynlabs.com/product/stockpilot/">StockPilot, an offline Flutter POS whose data lives in local Hive boxes</a>, is the kind of codebase this guide was written for. Its latest release made this move: StockPilot now runs on <code>hive_ce</code>, with the same data format as before.</p>
<h2>Moving to GenerateAdapters (optional)</h2>
<p><code>hive_ce</code> would rather you stop annotating models with <code>@HiveType</code> and <code>@HiveField</code> and list them in one <code>@GenerateAdapters</code> annotation. You do not need this to migrate. If you do it, the <a href="https://docs.hive.isar.community/migrations/hive_types_to_generate_adapters.md">documented route</a> worked for us:</p>
<ol>
<li>Move any <code>@HiveField</code> default values into constructor parameter defaults. Our test model had none, so we did not exercise this step.</li>
<li>Enable the migrator builder in <code>build.yaml</code> and run <code>build_runner</code>:</li>
</ol>
<pre><code class="language-yaml">targets:
  $default:
    builders:
      hive_ce_generator|hive_schema_migrator:
        enabled: true
</code></pre>
<ol start="3">
<li>It writes <code>lib/hive/hive_adapters.dart</code> containing <code>@GenerateAdapters([AdapterSpec&lt;Product&gt;(), AdapterSpec&lt;Category&gt;()])</code>, a <code>lib/hive/hive_adapters.g.yaml</code> with your existing typeIds and field indexes preserved, and a registrar.</li>
<li>Revert <code>build.yaml</code>, remove the annotations and <code>part</code> directives from your models, and build again.</li>
</ol>
<p>Our Hive 2 data still read back identically. Two things caught us that the docs do not mention.</p>
<p><strong>The registrar file moves.</strong> During the migrator run it is written to <code>lib/hive_registrar.g.dart</code>. After the final build it lives at <code>lib/hive/hive_registrar.g.dart</code>, so the old import breaks with <code>Error when reading 'lib/hive_registrar.g.dart'</code>. Update the import in <code>main.dart</code>.</p>
<p><strong>The <code>.g.yaml</code> becomes the source of truth for field indexes.</strong> Its header says to check it into version control. Do that. Renaming a field now means editing the yaml by hand, as the docs say. We did not test losing the file, but regenerating without it risks reassigned indexes, which is the kind of mistake that corrupts reads quietly.</p>
<h2>Deprecations the analyzer will not flag</h2>
<p>hive_ce's <a href="https://docs.hive.isar.community/deprecated/deprecation_policy.md">deprecation policy</a> is that APIs are never marked deprecated in code, because the project aims never to introduce breaking changes. So your build stays quiet while the docs list these as replaced:</p>
<ul>
<li><code>@HiveType</code> and <code>@HiveField</code>, in favour of <code>GenerateAdapters</code></li>
<li><code>HiveObject</code></li>
<li><code>HiveList</code></li>
<li><code>ValueListenable</code> and <code>box.listenable()</code>, in favour of <code>box.watch()</code></li>
</ul>
<p>None of this has to change during the migration. It matters later, because <code>HiveObject</code> and <code>HiveList</code> are what block <code>IsolatedHive</code>, the multi-isolate API added in 2.11.0. Do not adopt it in the migration branch. The <a href="https://docs.hive.isar.community/advanced/isolates.md">isolates docs</a> say that if you use it, you must use it everywhere in place of <code>Hive</code>; it does not support <code>HiveObject</code> or <code>HiveList</code>, and most calls become async. That is a refactor of every data access in the app.</p>
<p>The same 2.11.0 release tightened some type rules: boxes of type <code>Map</code> must be <code>Map&lt;dynamic, dynamic&gt;</code>, boxes of type <code>Iterable</code> must be <code>Iterable&lt;dynamic&gt;</code>, and custom objects in a <code>BoxCollection</code> must be JSON-serializable. If you open something like <code>Box&lt;Map&lt;String, dynamic&gt;&gt;</code> today, find it before you upgrade.</p>
<h2>Pre-migration checklist</h2>
<ol>
<li>Copy real box files off a test device or staging install.</li>
<li>In a Flutter app, grep for typeId 200 and 201.</li>
<li>Run <code>flutter pub deps</code> and look for <code>hive</code>, <code>hive_flutter</code> or <code>hive_generator</code>.</li>
<li>Upgrade or override any package still on <code>hive</code>, starting with <code>hydrated_bloc</code> 9.x.</li>
<li>Search for boxes typed as a <code>Map</code> or <code>Iterable</code> with non-dynamic type arguments.</li>
<li>Confirm Dart 3.4 or later and, for <code>hive_ce_flutter</code> 2.4.0, Flutter 3.44.0 or later.</li>
<li>Swap the three packages and every import.</li>
<li>Open the copied boxes with the new build and compare every record type.</li>
<li>Clear CI caches so no stale <code>.g.dart</code> or resolved <code>hive</code> survives.</li>
</ol>
<h2>What not to do</h2>
<ul>
<li><strong>Do not renumber a model's typeId</strong> to dodge the 200/201 collision. Move the Flutter adapters instead.</li>
<li><strong>Do not use a typeId above 223</strong> until the migrated release has proven itself. It ends your rollback option.</li>
<li><strong>Do not set <code>hive_ce_generator: ^2.x</code>.</strong> The generator is on 1.x.</li>
<li><strong>Do not adopt <code>IsolatedHive</code> in the migration branch.</strong></li>
<li><strong>Do not leave the <code>.g.yaml</code> out of git</strong> if you move to <code>GenerateAdapters</code>.</li>
</ul>
<h2>Where to go from here</h2>
<p>If you would rather start from apps whose local storage layer is already built and running without a server, browse <a href="https://stacklynlabs.com/products/?cat=mobile-applications">our offline-first Flutter app templates</a>. And since an encrypted box is only as safe as the place you keep its key, <a href="https://stacklynlabs.com/blog/securing-local-first-applications-a-flutter-architecture-study/">securing local-first applications in Flutter</a> covers where that key should live.</p>
<h2>References</h2>
<ul>
<li><a href="https://pub.dev/packages/hive_ce">hive_ce on pub.dev</a>, <a href="https://pub.dev/packages/hive_ce_flutter">hive_ce_flutter</a> and <a href="https://pub.dev/packages/hive_ce_generator">hive_ce_generator</a></li>
<li><a href="https://docs.hive.isar.community/migrations/hive_to_hive_ce.md">Hive CE docs: migrating from Hive v2</a></li>
<li><a href="https://github.com/IO-Design-Team/hive_ce/blob/main/hive_flutter/CHANGELOG.md">hive_ce_flutter changelog</a>, for the 200/201 registration (2.0.0) and configurable IDs (2.3.0)</li>
<li><a href="https://github.com/IO-Design-Team/hive_ce/blob/main/hive/CHANGELOG.md">hive_ce changelog</a>, for the 65439 typeId limit (2.10.0) and the 2.11.0 type rules</li>
<li>GitHub issues <a href="https://github.com/IO-Design-Team/hive_ce/issues/62">#62</a>, <a href="https://github.com/IO-Design-Team/hive_ce/issues/105">#105</a>, <a href="https://github.com/IO-Design-Team/hive_ce/issues/182">#182</a> and <a href="https://github.com/IO-Design-Team/hive_ce/issues/291">#291</a></li>
<li><a href="https://docs.hive.isar.community/migrations/transitive_hive_dependencies.md">Hive CE docs: transitive Hive dependencies</a> and <a href="https://github.com/IO-Design-Team/hive_ce/tree/main/overrides/hive">the override package in the hive_ce repository</a></li>
<li><a href="https://docs.hive.isar.community/migrations/hive_types_to_generate_adapters.md">Hive CE docs: HiveTypes to GenerateAdapters</a></li>
</ul>
<hr />
<p><em>Further reading: <a href="https://stacklynlabs.com/blog/building-zero-latency-mobile-apps-hive-vs-isar-vs-sqlite-choosing-a-flutter-local-database-in-2026/">Choosing a Flutter local database in 2026</a></em></p>
]]></content:encoded></item></channel></rss>