tursodatabase/turso · critical

Turso native module not loaded

Error message

Turso native module not loaded

What it means

Thrown by initLocalDatabase() during connect() when the JSI global __TursoProxy is not present on the JS runtime. The React Native binding is a thin TypeScript layer over a C++ JSI module that installs __TursoProxy as a runtime global (cpp/TursoHostObject.cpp). If the native part of @tursodatabase/sync-react-native was never built, linked, or is running in a runtime without JSI, the global is undefined and every local-only Database construction fails.

Solutions

  1. Disable remote JS debugging (Chrome debugger) — JSI only works with on-device/Hermes debugging via Flipper or the new debugger; then reload
  2. Rebuild the native app completely: `cd ios && pod install && cd .. && npx react-native run-ios` (or `./gradlew assembleDebug` on Android) so the JSI host object is compiled in
  3. If using Expo, switch from Expo Go to a development build (`npx expo run:ios` / `run-android`) since Expo Go cannot load custom native modules
  4. Verify android/build.gradle has minSdkVersion 21+ and that the package is autolinked (check it appears in `pod install` output / MainActivity modules)
  5. As a last resort, clean and rebuild: `watchman watch-del-all`, delete node_modules, ios/Pods, and build directories, then reinstall

Example fix

// before: app works in normal mode but throws 'Turso native module not loaded' when remote debugging
// Dev Menu -> Debug JS Remotely -> reload:
const db = new Database({ path: getDbPath('local.db') });
await db.connect(); // throws: __TursoProxy is undefined in the Chrome debug runtime

// after: keep JS execution on device (Hermes) and rebuild native after install
// package.json scripts stay the same; just avoid remote JS debugging and rebuild:
//   cd ios && pod install && cd ..
//   npx react-native run-ios
const db = new Database({ path: getDbPath('local.db') });
await db.connect();
Defensive patterns

Strategy: validation

Validate before calling

// Before constructing a Database, confirm the JSI global exists
import { getDbPath, Database } from '@tursodatabase/sync-react-native';

declare const __TursoProxy: unknown;

export function nativeModuleAvailable(): boolean {
  return typeof __TursoProxy !== 'undefined';
}

if (!nativeModuleAvailable()) {
  throw new Error(
    'Turso native module missing: rebuild the app (pod install / gradle) and disable remote JS debugging'
  );
}
const db = new Database({ path: getDbPath('local.db') });

Type guard

declare const __TursoProxy: unknown;

function hasTursoNative(globalThis: Record<string, unknown>): boolean {
  return typeof globalThis['__TursoProxy'] !== 'undefined';
}

Try / catch

try {
  await db.connect();
} catch (e) {
  if (e instanceof Error && e.message.includes('native module not loaded')) {
    // Environment problem, not a data problem: instruct rebuild / disable remote debug
    showSetupError('Rebuild the native app and disable remote JS debugging (JSI required).');
  }
  throw e;
}

Prevention

When it happens

Trigger: Creating `new Database({ path })` (no url) and calling `await db.connect()` while __TursoProxy is undefined: running the app without rebuilding the native binary after adding the dependency, skipping `cd ios && pod install`, debugging JS remotely in Chrome (the Chrome remote debugger replaces the JSI runtime with a plain JS engine that has no JSI globals), or running inside Expo Go where custom native code is not included.

Common situations: Fresh install where `npm install @tursodatabase/sync-react-native` ran but the iOS pods / Android gradle build were never refreshed; switching a project to the new architecture or upgrading React Native without rebuilding the app binary; enabling 'Debug JS Remotely' which detaches JSI; using Expo Go instead of a development build (`npx expo run:ios`).

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/19c1582ea57e0ae7. Report an issue: GitHub.

Appendix: source

Thrown at bindings/react-native/src/Database.ts:122

    if (this._connected) {
      return;
    }

    if (this._isSync) {
      await this.initSyncDatabase();
    } else {
      this.initLocalDatabase();
    }

    this._connected = true;
  }

  /**
   * Initialize local-only database
   */
  private initLocalDatabase(): void {
    if (typeof __TursoProxy === 'undefined') {
      throw new Error('Turso native module not loaded');
    }

    const dbConfig = {
      path: this._opts.path,
      async_io: false, // use blocking IO for local database
    };

    // Create native database (path normalization happens in C++ JSI layer)
    this._nativeDb = __TursoProxy.newDatabase(this._opts.path, dbConfig);

    // Open database
    this._nativeDb.open();

    // Get connection
    this._connection = this._nativeDb.connect();
  }

  /**

View on GitHub (pinned to 244cde92a7)