# Migrate Hive to hive_ce: What Breaks After the Pubspec Swap

*Originally published on [Stacklyn Labs](https://stacklynlabs.com/blog/migrate-hive-to-hive-ce/).*

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](https://stacklynlabs.com/blog/building-zero-latency-mobile-apps-hive-vs-isar-vs-sqlite-choosing-a-flutter-local-database-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:

```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
```

Then every import changes:

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

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](https://github.com/IO-Design-Team/hive_ce/issues/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](https://github.com/IO-Design-Team/hive_ce/issues/105), filed by a developer migrating from the original packages. In [issue #291](https://github.com/IO-Design-Team/hive_ce/issues/291), closed February 2026, the complaint was that the reserved IDs were undocumented.

Run this before you touch the pubspec:

```bash
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:

```dart
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](https://github.com/IO-Design-Team/hive_ce/issues/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):

```bash
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:

```text
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](https://docs.hive.isar.community/migrations/transitive_hive_dependencies.md), which we used as is:

```yaml
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.

If you're on Isar instead, the original `isar_generator` holds your toolchain back in the same way, and its Android binaries add a deadline of their own. We tested [the Isar alternatives for Flutter against a real Isar 3 file](https://stacklynlabs.com/blog/isar-alternatives-flutter/).

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](https://stacklynlabs.com/product/stockpilot/), is the kind of codebase this guide was written for. Its latest release made this move: StockPilot now runs on `hive_ce`, with the same data format as before.

## 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](https://docs.hive.isar.community/migrations/hive_types_to_generate_adapters.md) 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`:

```yaml
targets:
  $default:
    builders:
      hive_ce_generator|hive_schema_migrator:
        enabled: true
```

3. 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.
4. 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](https://docs.hive.isar.community/deprecated/deprecation_policy.md) 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](https://docs.hive.isar.community/advanced/isolates.md) 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](https://stacklynlabs.com/products/?cat=mobile-applications). And since an encrypted box is only as safe as the place you keep its key, [securing local-first applications in Flutter](https://stacklynlabs.com/blog/securing-local-first-applications-a-flutter-architecture-study/) covers where that key should live.

## References

- [hive_ce on pub.dev](https://pub.dev/packages/hive_ce), [hive_ce_flutter](https://pub.dev/packages/hive_ce_flutter) and [hive_ce_generator](https://pub.dev/packages/hive_ce_generator)
- [Hive CE docs: migrating from Hive v2](https://docs.hive.isar.community/migrations/hive_to_hive_ce.md)
- [hive_ce_flutter changelog](https://github.com/IO-Design-Team/hive_ce/blob/main/hive_flutter/CHANGELOG.md), for the 200/201 registration (2.0.0) and configurable IDs (2.3.0)
- [hive_ce changelog](https://github.com/IO-Design-Team/hive_ce/blob/main/hive/CHANGELOG.md), for the 65439 typeId limit (2.10.0) and the 2.11.0 type rules
- GitHub issues [#62](https://github.com/IO-Design-Team/hive_ce/issues/62), [#105](https://github.com/IO-Design-Team/hive_ce/issues/105), [#182](https://github.com/IO-Design-Team/hive_ce/issues/182) and [#291](https://github.com/IO-Design-Team/hive_ce/issues/291)
- [Hive CE docs: transitive Hive dependencies](https://docs.hive.isar.community/migrations/transitive_hive_dependencies.md) and [the override package in the hive_ce repository](https://github.com/IO-Design-Team/hive_ce/tree/main/overrides/hive)
- [Hive CE docs: HiveTypes to GenerateAdapters](https://docs.hive.isar.community/migrations/hive_types_to_generate_adapters.md)

---

*Further reading: [Choosing a Flutter local database in 2026](https://stacklynlabs.com/blog/building-zero-latency-mobile-apps-hive-vs-isar-vs-sqlite-choosing-a-flutter-local-database-in-2026/)*

