{"id":16023,"library":"expo-sqlite","title":"Expo SQLite","description":"expo-sqlite provides a robust interface for local SQLite database persistence within Expo and React Native applications. As of version 55.0.15, it integrates seamlessly with Expo SDK 55. New Expo SDK versions, and consequently updates to expo-sqlite, are typically released three times per year, aligning with the React Native release cadence. This package offers a modern promise-based API for core database operations, including creating tables, inserting, querying, and managing transactions. Its primary differentiator is the streamlined integration into the Expo ecosystem, abstracting away complex native module setup for React Native developers. It is a fundamental tool for building offline-first features and for efficient, structured local data storage, distinguishing itself from simpler key-value stores like `AsyncStorage` when complex queries or relationships are required.","status":"active","version":"55.0.15","language":"javascript","source_language":"en","source_url":"https://github.com/expo/expo","tags":["javascript","react-native","expo","sqlite","sql","storage","async-storage","typescript"],"install":[{"cmd":"npm install expo-sqlite","lang":"bash","label":"npm"},{"cmd":"yarn add expo-sqlite","lang":"bash","label":"yarn"},{"cmd":"pnpm add expo-sqlite","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core Expo runtime environment and build tooling.","package":"expo","optional":false},{"reason":"React's component model and hooks for state management in React Native applications.","package":"react","optional":false},{"reason":"The underlying framework for building native mobile applications.","package":"react-native","optional":false}],"imports":[{"note":"Since Expo SDK 49, `openDatabase` is a direct named export. The previous pattern of `SQLite.openDatabase` from a namespace import is deprecated and will result in errors.","wrong":"import * as SQLite from 'expo-sqlite'; const db = SQLite.openDatabase('name.db');","symbol":"openDatabase","correct":"import { openDatabase } from 'expo-sqlite';"},{"note":"Introduced in Expo SDK 49, `openDatabaseAsync` provides a modern promise-based API. Prefer this over the callback-based `openDatabase` for new code. CommonJS `require` is not supported for `expo-sqlite` in recent SDK versions.","wrong":"const { openDatabaseAsync } = require('expo-sqlite');","symbol":"openDatabaseAsync","correct":"import { openDatabaseAsync } from 'expo-sqlite';"},{"note":"This type definition is crucial for TypeScript users to correctly type database instances returned by `openDatabase` or `openDatabaseAsync`.","symbol":"SQLiteDatabase","correct":"import { SQLiteDatabase } from 'expo-sqlite';"}],"quickstart":{"code":"import { openDatabase, SQLiteDatabase } from 'expo-sqlite';\nimport React, { useState, useEffect } from 'react';\nimport { View, Text, Button, Alert, StyleSheet } from 'react-native';\n\nconst db: SQLiteDatabase = openDatabase('my_app_data.db');\n\nexport default function App() {\n  const [items, setItems] = useState<string[]>([]);\n\n  useEffect(() => {\n    db.transaction(tx => {\n      tx.executeSql(\n        'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY NOT NULL, text TEXT NOT NULL);',\n        [],\n        () => console.log('Table \"notes\" created or already exists.'),\n        (_, error) => {\n          console.error('Error creating table:', error);\n          return true; // Indicate transaction should rollback on error\n        }\n      );\n    },\n    (error) => console.error('Transaction error:', error),\n    () => {\n      console.log('Database initialization complete.');\n      fetchNotes();\n    });\n  }, []);\n\n  const addNote = async () => {\n    const newNote = `Note ${Date.now()}`;\n    db.transaction(tx => {\n      tx.executeSql(\n        'INSERT INTO notes (text) VALUES (?);',\n        [newNote],\n        () => {\n          Alert.alert('Success', `Added \"${newNote}\"`);\n          fetchNotes();\n        },\n        (_, error) => {\n          console.error('Error adding note:', error);\n          return true;\n        }\n      );\n    });\n  };\n\n  const fetchNotes = () => {\n    db.transaction(tx => {\n      tx.executeSql(\n        'SELECT * FROM notes;',\n        [],\n        (_, { rows }) => {\n          setItems(rows._array.map((item: any) => item.text));\n        },\n        (_, error) => {\n          console.error('Error fetching notes:', error);\n          return true;\n        }\n      );\n    });\n  };\n\n  return (\n    <View style={styles.container}>\n      <Text style={styles.title}>SQLite Notes</Text>\n      <Button title=\"Add New Note\" onPress={addNote} />\n      <Button title=\"Refresh Notes\" onPress={fetchNotes} />\n      <View style={styles.notesContainer}>\n        {items.length === 0 ? <Text>No notes yet.</Text> : items.map((item, index) => (\n          <Text key={index} style={styles.noteItem}>- {item}</Text>\n        ))}\n      </View>\n    </View>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n    paddingTop: 50\n  },\n  title: {\n    fontSize: 24,\n    marginBottom: 20\n  },\n  notesContainer: {\n    marginTop: 20\n  },\n  noteItem: {\n    marginVertical: 5\n  }\n});","lang":"typescript","description":"This quickstart demonstrates how to open a SQLite database, create a table, insert new notes, and fetch all existing notes, displaying them in a React Native component. It uses the modern promise-based API and proper error handling within transactions."},"warnings":[{"fix":"Update your import statements from `import * as SQLite from 'expo-sqlite'; const db = SQLite.openDatabase(...)` to `import { openDatabase } from 'expo-sqlite'; const db = openDatabase(...)` for callback-based, or `import { openDatabaseAsync } from 'expo-sqlite'; const db = await openDatabaseAsync(...)` for promise-based.","message":"Starting with Expo SDK 49, the primary API for opening a database changed. You must now import `openDatabase` (or `openDatabaseAsync`/`openDatabaseSync`) directly as a named export. The legacy `import * as SQLite` and then calling `SQLite.openDatabase` is no longer supported and will cause runtime errors.","severity":"breaking","affected_versions":">=49.0.0"},{"fix":"Always use `async/await` with promise-based APIs (`openDatabaseAsync`, `runAsync`, `getAllAsync`) or ensure all logic dependent on a database operation's completion is placed within the success callback of the transaction or `executeSql` call.","message":"All SQLite operations (e.g., `executeSql`, transactions) are asynchronous. Failing to properly handle promises or callbacks can lead to race conditions, unexpected data states, or errors where operations complete out of order.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"If you need to backup or migrate data, implement application-level export/import functionality using other Expo modules like `expo-file-system` to read/write database content to user-accessible directories or cloud storage, or use `serializeAsync` / `deserializeDatabaseAsync` APIs.","message":"`expo-sqlite` databases are sandboxed to the application. Database files cannot be directly accessed by other apps or outside the application's secure storage area, and the database will be deleted if the application is uninstalled.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always use ES module import syntax: `import { openDatabase } from 'expo-sqlite';` or `import { openDatabaseAsync } from 'expo-sqlite';`. Ensure your project's Metro/Babel configuration correctly handles ESM.","message":"Attempting to use `require('expo-sqlite')` will result in an `ERR_REQUIRE_ESM` error in modern Expo SDKs. `expo-sqlite` is published as an ES Module (ESM), and direct CommonJS `require()` is not supported.","severity":"gotcha","affected_versions":">=49.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Verify that the table was correctly created before attempting to query or modify it. Check for typos in the table name in both your `CREATE TABLE` and subsequent `SELECT`/`INSERT`/`UPDATE` statements.","cause":"The SQL query references a table name that does not exist or is misspelled in the database schema.","error":"Error: no such table: MyTable"},{"fix":"Change your import to `import { openDatabase } from 'expo-sqlite';` for the callback API or `import { openDatabaseAsync } from 'expo-sqlite';` for the promise API, and use `openDatabase(...)` or `await openDatabaseAsync(...)` directly.","cause":"You are likely using an older import pattern (`import * as SQLite from 'expo-sqlite'; SQLite.openDatabase`) with a newer Expo SDK version that expects direct named exports.","error":"TypeError: _expo_sqlite__WEBPACK_IMPORTED_MODULE_0__.openDatabase is not a function"},{"fix":"Ensure that all database modifications are wrapped within a single transaction. Avoid opening multiple simultaneous database connections for writes. If using promise-based APIs, ensure `await` is used correctly to prevent concurrent access.","cause":"Concurrent write operations are attempting to access the database simultaneously without proper transaction management, or a previous transaction was not properly closed.","error":"Error: Database is locked"},{"fix":"Migrate all `require('expo-sqlite')` statements to `import { openDatabase } from 'expo-sqlite';` (or `openDatabaseAsync`). Ensure your build environment (e.g., Metro, Babel) is configured to handle ESM properly.","cause":"Your project is attempting to import `expo-sqlite` using CommonJS `require()` syntax, but `expo-sqlite` is an ES Module (ESM) in recent Expo SDKs.","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module C:\\path\\to\\node_modules\\expo-sqlite\\build\\index.js not supported."}],"ecosystem":"npm"}