Expo SQLite

55.0.15 · active · verified Tue Apr 21

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.

Common errors

Warnings

Install

Imports

Quickstart

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.

import { openDatabase, SQLiteDatabase } from 'expo-sqlite';
import React, { useState, useEffect } from 'react';
import { View, Text, Button, Alert, StyleSheet } from 'react-native';

const db: SQLiteDatabase = openDatabase('my_app_data.db');

export default function App() {
  const [items, setItems] = useState<string[]>([]);

  useEffect(() => {
    db.transaction(tx => {
      tx.executeSql(
        'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY NOT NULL, text TEXT NOT NULL);',
        [],
        () => console.log('Table "notes" created or already exists.'),
        (_, error) => {
          console.error('Error creating table:', error);
          return true; // Indicate transaction should rollback on error
        }
      );
    },
    (error) => console.error('Transaction error:', error),
    () => {
      console.log('Database initialization complete.');
      fetchNotes();
    });
  }, []);

  const addNote = async () => {
    const newNote = `Note ${Date.now()}`;
    db.transaction(tx => {
      tx.executeSql(
        'INSERT INTO notes (text) VALUES (?);',
        [newNote],
        () => {
          Alert.alert('Success', `Added "${newNote}"`);
          fetchNotes();
        },
        (_, error) => {
          console.error('Error adding note:', error);
          return true;
        }
      );
    });
  };

  const fetchNotes = () => {
    db.transaction(tx => {
      tx.executeSql(
        'SELECT * FROM notes;',
        [],
        (_, { rows }) => {
          setItems(rows._array.map((item: any) => item.text));
        },
        (_, error) => {
          console.error('Error fetching notes:', error);
          return true;
        }
      );
    });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>SQLite Notes</Text>
      <Button title="Add New Note" onPress={addNote} />
      <Button title="Refresh Notes" onPress={fetchNotes} />
      <View style={styles.notesContainer}>
        {items.length === 0 ? <Text>No notes yet.</Text> : items.map((item, index) => (
          <Text key={index} style={styles.noteItem}>- {item}</Text>
        ))}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: 50
  },
  title: {
    fontSize: 24,
    marginBottom: 20
  },
  notesContainer: {
    marginTop: 20
  },
  noteItem: {
    marginVertical: 5
  }
});

view raw JSON →