Expo SQLite Integration with Drizzle and React Native

In this guide, we’ll explore how to integrate SQLite in a React Native app using Expo and Drizzle ORM. This setup allows for robust database management and schema migration within mobile applications.

Installation

First, add the necessary packages to the project:

yarn add drizzle-orm expo-sqlite@next
yarn add -D babel-plugin-inline-import drizzle-kit

Initialization

To initialize, update configuration files for Babel and Metro, and set up Drizzle.

1. Update Configuration Files

Adjust babel.config.js, metro.config.js, and drizzle.config.ts as follows:

// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: [["inline-import", { extensions: [".sql"] }]],
  };
};

If metro.config.js doesn’t exist, create it with the following content:

// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push("sql");
module.exports = config;

Similarly, create drizzle.config.ts if it’s missing:

// drizzle.config.ts
import type { Config } from "drizzle-kit";

export default {
  driver: "expo",
} satisfies Config;

After updating these files, restart development server to apply the changes.

2. Create and Manage Migrations

Set up and manage database schema with migrations.

2.1 Create the Database Schema

Create a new file schema.ts in ./db/schema.ts and define schema:

// schema.ts
import { integer, text, sqliteTable } from "drizzle-orm/sqlite-core";

export const table = sqliteTable("table", {
  id: integer("id").primaryKey(),
  amount: integer("amount").notNull(),
  note: text("note"),
});

Then, update drizzle.config.ts to include the schema and output directory:

// drizzle.config.ts
import type { Config } from "drizzle-kit";

export default {
  schema: "./db/schema.ts",
  out: "./drizzle",
  driver: "expo",
} satisfies Config;

2.2 Generate Migrations

Generate the migration files by running:

npx drizzle-kit generate:sqlite

This command creates necessary migration files in the ./drizzle directory.

2.3 Apply Migrations at Runtime

Use the useMigrations hook from Drizzle in App.tsx to run migrations when the app starts:

// App.tsx
import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite/next";
import { useMigrations } from "drizzle-orm/expo-sqlite/migrator";
import migrations from "./drizzle/migrations";

const expoDb = openDatabaseSync("[DB_NAME]");
const db = drizzle(expoDb);

export default function App() {
  const { success, error } = useMigrations(db, migrations);
  if (error) {
    return (
      <View>
        <Text>Migration error: {error.message}</Text>
      </View>
    );
  }
  if (!success) {
    return (
      <View>
        <Text>Migration is in progress...</Text>
      </View>
    );
  }
  // Return application component here
}

3. All Set!

The app is now configured to use SQLite with Drizzle ORM. For further information and to continue developing the app, refer to the Drizzle ORM documentation.