Skip to main content
Version: 0.30.0-beta.8

Migrating from WatermelonDB

NitromelonDB is a maintained fork of WatermelonDB (@nozbe/watermelondb). Models, schema, queries, writers, sync, LokiJS, and the web adapters are the same API. What changed is the npm package name, native linking, and a few React Native SQLite requirements.

If you are starting a new app, skip this page and go to Installation.

What you keep

Your existing SQLite files, schema version, migrations, and model classes keep working. This is a library swap, not a data migration.

If you're also adding seed

NitromelonDB's seed option (see Database seeding) tracks "did this already run" with a marker that's new in NitromelonDB and never existed under WatermelonDB. On a database carried over from WatermelonDB, every configured step looks unapplied and will run -- even though the table may already have real user data. If you add seed as part of this swap, read the "Where to be careful in production" section there first.

1. Swap the npm package

yarn remove @nozbe/watermelondb
yarn add nitromelondb

# (or with npm:)
npm uninstall @nozbe/watermelondb
npm install nitromelondb

rxjs ^7.8.0 is both a dependency and a peer. The dependency is what yarn add nitromelondb / npm install nitromelondb installs for you. The peer is so Yarn/npm hoist a single copy if the app already has RxJS (two copies break Observable / Subscription types). You do not add it yourself.

On React Native (iOS, Android, and Windows), also add the Nitro peer and rebuild native code — skip this if react-native-nitro-modules is already in the app (do not double-install it):

yarn add react-native-nitro-modules

Use react-native-nitro-modules 0.35.2 or newer. NitromelonDB is built against 0.36.x; a * peer range used to hide ABI mismatches that only show up in Xcode or Gradle.

react-native-nitro-modules is optional for web / Node / Electron. It is required for SQLite on iOS, Android, and Windows.

After the JS swap you still need pod install and a full native rebuild. Metro reload is not enough.

2. Rewrite imports

Replace the old scope in JavaScript/TypeScript source, tests, and Jest mocks — not in leftover native project files (see iOS, Android, and Windows):

FromTo
@nozbe/watermelondbnitromelondb
@nozbe/watermelondb/adapters/sqlitenitromelondb/adapters/sqlite
@nozbe/watermelondb/adapters/lokijsnitromelondb/adapters/lokijs
@nozbe/watermelondb/decoratorsnitromelondb/decorators
@nozbe/watermelondb/reactnitromelondb/react
@nozbe/watermelondb/syncnitromelondb/sync
@nozbe/watermelondb/Schema/migrationsnitromelondb/Schema/migrations
@nozbe/watermelondb/utils/common/randomIdnitromelondb/utils/common/randomId
@nozbe/watermelondb/utils/common/loggernitromelondb/utils/common/logger

A project-wide replace of @nozbe/watermelondbnitromelondb is enough for JS/TS imports. It is not enough for native files.

Leave other @nozbe/* packages alone. simdjson and SQLite are vendored inside NitromelonDB (native/vendor/).

// before
import { Database, Q } from '@nozbe/watermelondb'
import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite'
import { field, writer } from '@nozbe/watermelondb/decorators'
import { withObservables } from '@nozbe/watermelondb/react'
import { synchronize } from '@nozbe/watermelondb/sync'

// after
import { Database, Q } from 'nitromelondb'
import SQLiteAdapter from 'nitromelondb/adapters/sqlite'
import { field, writer } from 'nitromelondb/decorators'
import { withObservables } from 'nitromelondb/react'
import { synchronize } from 'nitromelondb/sync'

3. iOS

Autolinking picks up the NitromelonDB pod. Remove any WatermelonDB / simdjson / FMDB lines you added by hand — simdjson is compiled into NitromelonDB from vendored sources. You do not add a pod 'simdjson', pod 'FMDB', or pod 'NitromelonDB' line. FMDB is not used.

# Remove these lines if they are in your Podfile.
# Autolinking provides NitromelonDB. simdjson is compiled into that pod —
# there is no separate simdjson (or FMDB) pod to add.
#
# pod 'WatermelonDB', path: '../node_modules/@nozbe/watermelondb'
# pod 'NitromelonDB', path: '../node_modules/nitromelondb'
# pod 'simdjson', path: '../node_modules/@nozbe/simdjson', modular_headers: true

Then pod install (Expo: npx expo prebuild).

use_frameworks! :linkage => :static (common in RN Firebase apps) is supported. Prefer static linkage if you must use frameworks. See Installation — Bare React Native.

Bridging header (only if you import the native header yourself):

// before
#import <WatermelonDB/WatermelonDB.h>
#import <NitromelonDB/WatermelonDB.h>

// after
#import <NitromelonDB/NitromelonDB.h>
Do not retarget old header search paths

A project-wide path replace will turn node_modules/@nozbe/watermelondb/native/ios/.../SupportingFiles into node_modules/nitromelondb/native/ios/.../SupportingFiles, which is not a public include path. Delete those HEADER_SEARCH_PATHS / SupportingFiles entries from the pbxproj. Autolinking and the podspec set the headers.

Minimum iOS deployment target is 15.1.

4. Android

Nitro autolinks. Delete the old JSI Gradle module — do not retarget it:

  • include ':watermelondb-jsi' from android/settings.gradle
  • implementation project(':watermelondb-jsi') from android/app/build.gradle
  • WatermelonDBJSIPackage from MainApplication
There is no native/android-jsi

A string replace of @nozbe/watermelondbnitromelondb will produce:

project(':watermelondb-jsi').projectDir =
new File(rootProject.projectDir, '../node_modules/nitromelondb/native/android-jsi')

That path does not exist. Remove the whole JSI block. Do not point it at native/android either — that module autolinks.

Do not register WatermelonDBPackage by hand — that is the old architecture. Autolinking is required.

The Android Java package is com.nitromelondb (it used to be com.nozbe.watermelondb). Update any R8 / Proguard keep rule:

-keep class com.nitromelondb.** { *; }

Turbo-sync JSON injection now goes through com.nitromelondb.NitromelonNative.provideSyncJson.

Minimum Android SDK is 24.

5. Windows

RNW New Architecture (0.84 / WinAppSDK) uses Nitro, not the old UWP WMDatabaseBridge JSI installer. Autolinking picks up native/windows.

Add this to the app react-native.config.js so RNW does not look for a react-native-nitro-modules Windows project (nitro#168):

const { windowsAppDependencies } = require('nitromelondb/windows-autolink')

module.exports = {
dependencies: windowsAppDependencies(),
}

See Installation — Windows.

6. Expo

The config plugin is optional for bare React Native. Autolinking is what actually links SQLite. On Expo, add the plugin so prebuild keeps the New Architecture on (it rejects "newArchEnabled": false).

You do not need @morrowdigital/watermelondb-expo-plugin (that package wired the old Android JSI module).

yarn remove @morrowdigital/watermelondb-expo-plugin

In app.json / app.config.js, replace it with "nitromelondb":

{
"expo": {
"plugins": ["nitromelondb"]
}
}

Then npx expo prebuild (or let EAS Build do it). Development builds, EAS Build, and EAS Update are supported. Expo Go is not. See Installation — Expo.

7. SQLiteAdapter on React Native

iOS and Android SQLite is Nitro-only. NativeModules interop is gone. The old React Native architecture (Paper / the legacy bridge) is not supported — enable the New Architecture (on by default in React Native 0.87; required on 0.83+ as well).

const adapter = new SQLiteAdapter({
schema,
migrations,
// `{ jsi: false }` throws on iOS/Android. Omit it, or leave `jsi: true`.
onSetUpError: error => {},
})
  • Do not pass { jsi: false } on React Native.
  • Web still uses LokiJS (or Node SQLite in Electron/Node).
  • Windows New Architecture uses Nitro (same HybridObject as iOS/Android). The UWP JSI installer is removed.

If SQLiteAdapter cannot create a native database, install react-native-nitro-modules and rebuild the app — Metro reload is not enough.

8. TypeScript (Flow and hand-written .d.ts are gone)

The library implementation is TypeScript. The published package ships index.d.ts next to compiled JS. Do not add tsconfig path aliases to node_modules/nitromelondb/src/*.ts or to a .d.ts file in isolation — those files are not what npm installs, and mapping the package onto them breaks Metro and Jest.

  • Delete @nozbe/watermelondb from Flow [libs] / .flowconfig if you had them.
  • Let TypeScript resolve nitromelondb from the package (no paths workaround).

App model code can stay JavaScript.

Flow / @nozbe/watermelondb/types → TypeScript

@nozbe/watermelondb/types is gone. Import replacements from nitromelondb:

Flow / old importTypeScript
RecordIdimport type { RecordId } from 'nitromelondb'
TableName<T> / ColumnNameimport type { TableName, ColumnName } from 'nitromelondb'
RelationId<T> or $Call<…> extractors (e.g. a NonNullableRelation helper)import type { RelationId } from 'nitromelondb'RelationId<Model> is string; RelationId<Model | null> is string | null
Associations, RawRecord, DirtyRawimport type { Associations } from 'nitromelondb/Model' and import type { RawRecord, DirtyRaw } from 'nitromelondb'
$Diff, $Rest, $ShapeTypeScript Omit, Partial, Pick

See Flow support removed and the TypeScript example.

@json sanitizers

json() is generic: json<TInput, TOutput>(column, (source: TInput) => TOutput). Typed sanitizers from WatermelonDB apps type-check, including ones that change the type ((source: string) => string[]). memo on the options object is optional (default false).

Custom Model.id

Model.id is assignable only inside collection.create() / prepareCreate():

await collection.create(record => {
record.id = serverId
})

Assigning record.id anywhere else throws. _raw.id and prepareCreateFromDirtyRaw still work.

9. Jest / Metro

  • Move __mocks__/@nozbe/watermelondb to __mocks__/nitromelondb (and the same for any subpath mocks).
  • Do not path-map nitromelondb to unpublished .ts sources or to a .d.ts file. The published package is compiled JS at the package root.
  • That compiled JS does not need transformIgnorePatterns for nitromelondb.
  • If a release bundle loads nitro.json and SQLite never opens, you are on 0.30.0-beta.1. Upgrade; do not patch require('.../nitro') yourself after that.

10. Platform floor

RequirementWatermelonDB 0.28NitromelonDB
Node.js18+ (typical)App Node version follows your React Native release. This repo's example/CI uses 22+.
React Native0.74+ in 0.28New Architecture required. Tested on 0.83+. examples/NotesApp uses Expo SDK 57 (RN 0.86). examples/NotesApp_windows uses RN 0.84.1 to match RNW 0.84. Old / Paper architecture is not supported.
iOS12+15.1
Android minSdk21 (typical)24
React Native Windowsexperimental UWP / JSIRNW 0.84 New Architecture (WinAppSDK). See Windows.
react-native-nitro-modulesn/a≥ 0.35.2 (optional peer on web)
rxjstransitivedependency + peer ^7.8.0 (installed with the package)

Checklist

  • yarn remove @nozbe/watermelondb && yarn add nitromelondb
  • yarn add react-native-nitro-modules if it is not already a dependency (>=0.35.2)
  • Replace @nozbe/watermelondbnitromelondb in JS/TS imports, Jest mocks, and path aliases — not in native JSI / SupportingFiles paths
  • Remove hand-copied pod 'WatermelonDB' / pod 'NitromelonDB' / pod 'simdjson' / pod 'FMDB' lines from the Podfile
  • Delete pbxproj SupportingFiles / old Watermelon header search paths; do not retarget them
  • Bridging header, if you import it: #import <NitromelonDB/NitromelonDB.h>
  • Delete watermelondb-jsi / WatermelonDBJSIPackage from Android. Do not retarget native/android-jsi
  • Windows: spread windowsAppDependencies() from nitromelondb/windows-autolink; remove UWP WatermelonDB.vcxproj / WMDatabaseBridge linking
  • Enable the New Architecture (old / Paper architecture is not supported)
  • Remove { jsi: false } from SQLiteAdapter on React Native
  • Expo: add "nitromelondb" to app.json plugins and remove @morrowdigital/watermelondb-expo-plugin. Bare apps can skip the plugin.
  • pod install and a full native rebuild (npx react-native run-ios / run-android / run-windows, or npx expo run:ios / run:android) — not a Metro reload

Then continue with Installation and Setup if anything in native linking is still missing.