Local-First

Migrate Hive to hive_ce: What Breaks After the Pubspec Swap

Your Flutter app runs on hive 2.2.3. It still opens its boxes and still ships. But flutter pub upgrade keeps stalling on hivegenerator, and the last stable hiv…

October 12, 2026•12 min read•By Stacklyn Labs
Migrate Hive to hive_ce: What Breaks After the Pubspec Swap

Your Flutter app runs on hive 2.2.3. It still opens its boxes and still ships. But flutter pub upgrade keeps stalling on hive_generator, and the last stable hive release on pub.dev is from June 2022. Meanwhile hive_ce, the community continuation of Hive v2, has overtaken the original: 1,317,184 downloads in the last 30 days against 1,131,007 for hive when we checked on October 12, 2026.

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 hive, or that one hive_ce feature removes your ability to roll back.

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 how hive_ce compares with Isar, drift and SQLite in 2026.

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 initFlutter comes from the hive_ce source, changelogs and issue tracker.

The swap the docs already cover

Three package names change in pubspec.yaml. These are the current versions on pub.dev as of October 12, 2026:

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

Then every import changes:

// 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';

The import change is not optional. With hive removed and the old imports left in place, the analyzer stops at uri_does_not_exist on package:hive/hive.dart.

Three small traps sit inside those few lines:

  • The generator is on 1.x, not 2.x. Issue #62 is a user who copied hive_ce's version number into hive_ce_generator: ^2.8.0+3 and got a version-solving failure.
  • The SDK floor is Dart 3.4. The README's getting-started snippet shows sdk: ^3.0.0, but all three packages declare ^3.4.0 on pub.dev.
  • hive_ce_flutter 2.4.0 needs Flutter 3.44.0 or later. On an older Flutter, ^2.4.0 will not resolve. Use hive_ce_flutter: ^2.3.4 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.

Your existing box files open unchanged

The migration page says Hive v4 data is not compatible. It never says outright that Hive 2 files are.

We tested it. With hive 2.2.3 and hive_generator 2.0.1 we wrote four boxes: a typed box of Product extends HiveObject (with String, double, enum, DateTime and List<String> fields, under both an auto-increment key and a string key), an untyped box holding a mixed map, a LazyBox, and an AES-encrypted box.

We saved what Hive 2 read back as a baseline, then opened the same files under hive_ce 2.20.2 in three states: after only the pubspec and import swap, after regenerating adapters with hive_ce_generator, and after a full move to GenerateAdapters. In all three, every value, every key and every HiveObject.key matched the baseline, including the lazy and encrypted boxes. No data migration step was needed.

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.

Check typeIds 200 and 201 before you upgrade a Flutter app

This is the biggest gap in the official guide, and it only affects Flutter apps.

Since hive_ce_flutter 2.0.0, a release its changelog marks as breaking, Hive.initFlutter() registers a ColorAdapter at typeId 200 and a TimeOfDayAdapter at typeId 201 for you. If one of your models already uses 200 or 201, your own registration throws There is already a TypeAdapter for typeId 200. That is issue #105, filed by a developer migrating from the original packages. In issue #291, closed February 2026, the complaint was that the reserved IDs were undocumented.

Run this before you touch the pubspec:

grep -rnE "typeId *[:=] *20[01]\b" lib/

It catches both @HiveType(typeId: 200) annotations and hand-written adapters with final int typeId = 201;.

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 hive_ce_flutter 2.3.0 their IDs are configurable. In the current source, initFlutter takes them as optional positional parameters:

Future<void> initFlutter([
  String? dir,
  HiveStorageBackendPreference backendPreference =
      HiveStorageBackendPreference.native,
  int? colorAdapterTypeId,      // default 200
  int? timeOfDayAdapterTypeId,  // default 201
  bool useMaterialUi = false,
])

Pick two IDs no model of yours uses. If you stored Color values through the old ecosystem's adapter, read issue #182 first: that format is not compatible, and a bug reading legacy colour data was only fixed in hive_ce_flutter 2.3.2.

Find any package that still pulls in hive

Your pubspec can be clean while your dependency tree is not. Two common sources of the original package:

  • hydrated_bloc 9.1.5 and older depend on hive ^2.0.0. It moved to hive_ce in 10.0.0, released January 2025.
  • hive_flutter 1.1.0 depends on hive, so a forgotten hive_flutter line brings it back.

Find them with this (use dart pub deps for a pure Dart package):

flutter pub deps | grep -E "\bhive(_flutter|_generator)? [0-9]"

Anything it prints is the original package, not the CE one.

What two copies of Hive do

We reproduced this with both packages installed. They run as two separate engines: identical(ce.Hive, old.Hive) returns false, and each has its own adapter registry and open boxes.

Opening the same box from both failed. On Windows the error was:

PathAccessException: lock failed, path = 'data_both\shared.lock'

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.

The override shim

The best fix is upgrading the offending package. If you cannot, the hive_ce repository ships a stand-in hive package under overrides/hive for exactly this case. This is the dependency_overrides entry from the Hive CE docs on transitive Hive dependencies, which we used as is:

dependency_overrides:
  hive:
    git:
      url: https://github.com/IO-Design-Team/hive_ce
      ref: 18f92b53295e9eb77ebd4830d905a72cd404a126
      path: overrides/hive

Pub resolved hive 0.0.0 from git ... (overridden). After that, identical() returned true, and a write through one import was visible through the other: one engine, one box.

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 ref when you upgrade. And you still list hive_ce as a direct dependency. Treat the shim as a bridge until the other package moves.

The one-way door: typeIds above 223

Rolling back works up to a point: data hive_ce wrote with the same model and plain types read back correctly in hive 2.2.3.

The point is typeId 224. Original Hive caps custom typeIds at 223, and hive_ce 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 hive 2.2.3 and got two different failures:

  • registering the adapter: HiveError: TypeId 300 not allowed.
  • opening the box without it: HiveError: Cannot read, unknown typeId: 21. Did you forget to register an adapter?

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.

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.

What changes in your adapters and toolchain

Your old generated .g.dart files compile against hive_ce as they are, so regeneration can wait if you want a smaller first diff. When you do run dart run build_runner build, three things change:

Old hive_generator output hive_ce_generator output Effect
final int typeId = 0; final typeId = 0; None
break; in enum adapter cases removed None
fields[1] as double (fields[1] as num).toDouble() A stored int no longer crashes a double field

The bigger change is what the old generator was holding back. In a fresh Dart 3.12 project, adding hive_generator 2.0.1 resolved analyzer 6.4.1, source_gen 1.5.0 and build_runner 2.4.13, and downgraded test and other packages. After switching to hive_ce_generator, the same project resolved analyzer 14.5.0, source_gen 4.3.0 and build_runner 2.16.2. If your app also uses freezed, json_serializable or any other generator, hive_generator 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.

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, StockPilot, an offline Flutter POS whose data lives in local Hive boxes, is the kind of codebase this guide was written for. It runs on the original hive package today, so the steps above are exactly the path if you want it on the maintained fork.

Moving to GenerateAdapters (optional)

hive_ce would rather you stop annotating models with @HiveType and @HiveField and list them in one @GenerateAdapters annotation. You do not need this to migrate. If you do it, the documented route worked for us:

  1. Move any @HiveField default values into constructor parameter defaults. Our test model had none, so we did not exercise this step.
  2. Enable the migrator builder in build.yaml and run build_runner:
targets:
  $default:
    builders:
      hive_ce_generator|hive_schema_migrator:
        enabled: true
  1. It writes lib/hive/hive_adapters.dart containing @GenerateAdapters([AdapterSpec<Product>(), AdapterSpec<Category>()]), a lib/hive/hive_adapters.g.yaml with your existing typeIds and field indexes preserved, and a registrar.
  2. Revert build.yaml, remove the annotations and part directives from your models, and build again.

Our Hive 2 data still read back identically. Two things caught us that the docs do not mention.

The registrar file moves. During the migrator run it is written to lib/hive_registrar.g.dart. After the final build it lives at lib/hive/hive_registrar.g.dart, so the old import breaks with Error when reading 'lib/hive_registrar.g.dart'. Update the import in main.dart.

The .g.yaml becomes the source of truth for field indexes. 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.

Deprecations the analyzer will not flag

hive_ce's deprecation policy 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:

  • @HiveType and @HiveField, in favour of GenerateAdapters
  • HiveObject
  • HiveList
  • ValueListenable and box.listenable(), in favour of box.watch()

None of this has to change during the migration. It matters later, because HiveObject and HiveList are what block IsolatedHive, the multi-isolate API added in 2.11.0. Do not adopt it in the migration branch. The isolates docs say that if you use it, you must use it everywhere in place of Hive; it does not support HiveObject or HiveList, and most calls become async. That is a refactor of every data access in the app.

The same 2.11.0 release tightened some type rules: boxes of type Map must be Map<dynamic, dynamic>, boxes of type Iterable must be Iterable<dynamic>, and custom objects in a BoxCollection must be JSON-serializable. If you open something like Box<Map<String, dynamic>> today, find it before you upgrade.

Pre-migration checklist

  1. Copy real box files off a test device or staging install.
  2. In a Flutter app, grep for typeId 200 and 201.
  3. Run flutter pub deps and look for hive, hive_flutter or hive_generator.
  4. Upgrade or override any package still on hive, starting with hydrated_bloc 9.x.
  5. Search for boxes typed as a Map or Iterable with non-dynamic type arguments.
  6. Confirm Dart 3.4 or later and, for hive_ce_flutter 2.4.0, Flutter 3.44.0 or later.
  7. Swap the three packages and every import.
  8. Open the copied boxes with the new build and compare every record type.
  9. Clear CI caches so no stale .g.dart or resolved hive survives.

What not to do

  • Do not renumber a model's typeId to dodge the 200/201 collision. Move the Flutter adapters instead.
  • Do not use a typeId above 223 until the migrated release has proven itself. It ends your rollback option.
  • Do not set hive_ce_generator: ^2.x. The generator is on 1.x.
  • Do not adopt IsolatedHive in the migration branch.
  • Do not leave the .g.yaml out of git if you move to GenerateAdapters.

Where to go from here

If you would rather start from apps whose local storage layer is already built and running without a server, browse our offline-first Flutter app templates. And since an encrypted box is only as safe as the place you keep its key, securing local-first applications in Flutter covers where that key should live.

References

Stacklyn Labs
Written by Stacklyn Labs

Stacklyn Labs is a small studio publishing offline-first Flutter templates on CodeCanyon and Codester since 2025, and building custom Flutter and web apps for the teams who buy them.


More Articles

Related Posts

Marketplace Partner

Looking for Production-Ready Apps?

Save hundreds of development hours with our premium Flutter templates, Bootstrap web kits, and enterprise B2B source code.