Become a Gold Sponsor

Drizzle <> Expo SQLite

According to the official website, Expo is an ecosystem of tools to develop, build and ship applications on React Native. It’s powered by Hermes JavaScript runtime and Metro bundler, Drizzle Expo driver is built to natively support both.

Drizzle ORM has the best in class toolkit for Expo SQLite:

npm
yarn
pnpm
bun
npm i drizzle-orm expo-sqlite@next
npm i -D drizzle-kit
import { drizzle } from "drizzle-orm/expo-sqlite";
import { openDatabaseSync } from "expo-sqlite/next";

const expo = openDatabaseSync("db.db");
const db = drizzle(expo);

await db.select().from(users);

Live Queries

With useLiveQuery hook you can make any Drizzle query reactive:

import { useLiveQuery, drizzle } from 'drizzle-orm/expo-sqlite';
import { openDatabaseSync } from 'expo-sqlite/next';
import { Text } from 'react-native';
import * as schema from './schema';

const expo = openDatabaseSync('db.db', { enableChangeListener: true }); // <-- enable change listeners
const db = drizzle(expo);

const App = () => {
  // Re-renders automatically when data changes
  const { data } = useLiveQuery(db.select().from(schema.users));
  return <Text>{JSON.stringify(data)}</Text>;
};

export default App;

Expo SQLite migrations with Drizzle Kit

You can use Drizzle Kit for SQL migration generation.
Please make sure to check how Drizzle migrations work before proceeding.
Expo / React Native requires you to have SQL migrations bundled into the app and we’ve got you covered.

Install babel plugin

It’s necessary to bundle SQL migration files as string directly to your bundle.

npm install babel-plugin-inline-import

Update config files.

You will need to update babel.config.js, metro.config.js and drizzle.config.ts files

babel.config.js
module.exports = function(api) {
  api.cache(true);

  return {
    presets: ['babel-preset-expo'],
    plugins: [["inline-import", { "extensions": [".sql"] }]] // <-- add this
  };
};
metro.config.js
const { getDefaultConfig } = require('expo/metro-config');

/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);

config.resolver.sourceExts.push('sql'); // <--- add this

module.exports = config;

Make sure to have dialect: 'sqlite' and driver: 'expo' in Drizzle Kit config

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

export default {
  schema: './db/schema.ts',
  out: './drizzle',
  dialect: 'sqlite',
  driver: 'expo', // <--- very important
} satisfies Config;

Generate migrations

After creating SQL schema file and drizzle.config.ts file, you can generate migrations

npx drizzle-kit generate

Add migrations to your app

Now you need to import migrations.js file into your Expo/React Native app from ./drizzle folder. You can run migrations on application startup using our custom useMigrations migrations hook on in useEffect hook manually as you want.

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.db");

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 ...your application component;
}