{"id":29012947,"url":"https://github.com/webintellectual/drizzle-expo-setup-example","last_synced_at":"2025-06-25T19:05:15.641Z","repository":{"id":301004767,"uuid":"996156157","full_name":"webintellectual/drizzle-expo-setup-example","owner":"webintellectual","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-24T16:49:38.000Z","size":259,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-24T17:48:37.920Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webintellectual.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-04T14:33:34.000Z","updated_at":"2025-06-24T16:49:42.000Z","dependencies_parsed_at":"2025-06-24T17:48:40.736Z","dependency_job_id":"04ee8e2f-6d1d-4164-bd38-2e318eb5920e","html_url":"https://github.com/webintellectual/drizzle-expo-setup-example","commit_stats":null,"previous_names":["webintellectual/drizzle-expo-setup-example"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/webintellectual/drizzle-expo-setup-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webintellectual%2Fdrizzle-expo-setup-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webintellectual%2Fdrizzle-expo-setup-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webintellectual%2Fdrizzle-expo-setup-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webintellectual%2Fdrizzle-expo-setup-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webintellectual","download_url":"https://codeload.github.com/webintellectual/drizzle-expo-setup-example/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webintellectual%2Fdrizzle-expo-setup-example/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261937041,"owners_count":23232846,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-25T19:05:14.914Z","updated_at":"2025-06-25T19:05:15.617Z","avatar_url":"https://github.com/webintellectual.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"### **Have an expo project ready**\n\n- `$ npx create-expo-app@latest`\n- Go to the root directory of project and run: `$ npm run reset-project`\n- Make `src` directory in project root and shift `app` and `asset` to `src`\n- Update `app.json`\n\n### Writing Database Schema\n\n1. **Install `drizzle-orm` — The Runtime Library**\n    - **What it is**: A TypeScript ORM that runs in your app (e.g., React Native with Expo, Node.js, etc.).\n    - **Purpose**: It provides a **type-safe query builder** and handles actual database interactions (like `select`, `insert`, `update`, `delete`).\n    - **When it runs**: **At runtime** — in your production app code.\n    \n    You need this to write and run queries in your app.\n    \n    **`$ npm i drizzle-orm`**\n    \n2. **Write schema of your database using `drizzle-orm`**\n    \n    Create `src/db/schema.ts` \n    \n    ```python\n    import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';\n    \n    export const users = sqliteTable(\"users\", {\n      id: integer(\"id\").primaryKey(),\n      name: text(\"name\").notNull(),\n      email: text(\"email\").notNull(),\n    });\n    \n    ```\n    \n\n### Setting Up configuration files\n\n1. **Setup babel config**\n    \n    `$ npm install babel-plugin-inline-import`\n    \n    `$ npx expo customize babel.config.js`  (Skip this if you already have this file present)\n    \n    ```jsx\n    // babel.config.js\n    \n    module.exports = function(api) {\n      api.cache(true);\n    \n      return {\n        presets: ['babel-preset-expo'],\n        plugins: [[\"inline-import\", { \"extensions\": [\".sql\"] }]] // \u003c-- add this\n      };\n    };\n    ```\n    \n    Purpose of this setting:\n    \n    The `babel-plugin-inline-import` plugin allows you to import the contents of files (like `.sql`, `.graphql`, `.txt`, etc.) directly as strings within your JavaScript or TypeScript code. This is particularly useful for Drizzle ORM, which generates SQL migration files that need to be bundled into your application.\n    \n2. Setup Metro config\n    \n    `$ npx expo customize metro.config.js` (Skip this command if this file is already present in your project’s root)\n    \n    ```jsx\n    // metro.config.js\n    \n    const { getDefaultConfig } = require('expo/metro-config');\n    \n    /** @type {import('expo/metro-config').MetroConfig} */\n    const config = getDefaultConfig(__dirname);\n    \n    config.resolver.sourceExts.push('sql'); // \u003c--- add this\n    \n    module.exports = config;\n    ```\n    \n    By default, Metro only processes specific file extensions (like `.js`, `.jsx`, `.ts`, `.tsx`). Drizzle ORM generates `.sql` files for database migrations, which need to be bundled with your application. To ensure Metro recognizes and includes these `.sql` files during the bundling process, you need to explicitly add the `.sql` extension to the `sourceExts` array in your `metro.config.js`.\n    \n    This configuration tells Metro to treat `.sql` files as source files, allowing them to be imported and used within your JavaScript or TypeScript code.\n    \n3. **Install `drizzle-kit` — The CLI \u0026 Migration Tool**\n    - **What it is**: A development-time tool that generates migration SQL files and TypeScript types from your schema.\n    - **Purpose**: Helps you:\n        - Generate migration files (e.g., `CREATE TABLE` SQL)\n        - Sync your schema to the database\n        - Generate types that `drizzle-orm` uses\n    - **When it runs**: **Only during development**, via the CLI.\n    - You need this for:\n        - Setting up your schema safely\n        - Keeping your database and code in sync\n        - Using Drizzle Studio (which reads the generated schema)\n    \n    `$ **npm i -D drizzle-kit`** \n    \n4. **Create config file for drizzle kit and link db schema file there**\n    \n    A configuration file that is used by [Drizzle Kit](https://orm.drizzle.team/docs/kit-overview) and contains all the information about your database connection, migration folder and schema files.\n    \n    Create a file named `drizzle.config.ts` at the root of your project:\n    \n    ```jsx\n    // drizzle.config.ts\n    \n    import type { Config } from 'drizzle-kit';\n    \n    export default {\n    \tschema: './src/db/schema.ts',\n    \t// schema file is linked in the drizzle.config.ts so \n    \t// that drizzle kit can use it to migrate schema.\n    \t\n    \tout: './drizzle',\n      dialect: 'sqlite',\n    \tdriver: 'expo', // \u003c--- very important\n    } satisfies Config;\n    ```\n    \n\n### Generating Migrations (Converting schema written in TS to actual .sql file)\n\n`$ npx drizzle-kit generate` . It creates migration files in the `drizzle/` folder.\n\n\u003caside\u003e\n💡\n\nEvery time you change the schema of you database you need to run `npx drizzle-kit generate` to migrate to need schema. First time you do it for the purpose of creating initial schema.\n\n\u003c/aside\u003e\n\n### Install Expo-SQLite and Create Development Build\n\n1. Install expo sqlite: `$ npx expo install expo-sqlite` \n2. So, drizzle does not work in your expo go environment. You need to create a development build\n    - `$ npx expo prebuild --platform android` or `$ npx expo prebuild --platform android` or `$ npx expo prebuild`  for both builds\n    - `$ npx expo run:android`\n    - Reference:\n        \n        [Continuous Native Generation (CNG)](https://docs.expo.dev/workflow/continuous-native-generation/)\n        \n\n### Setup Root Layout for drizzle\n\n1. Define database name and use `openDatabaseSync` from expo-sqlite to create or open existing database with the database name defined.\n    \n    So far, this how your _layout.tsx will look like:\n    \n    ```jsx\n    import { Stack } from \"expo-router\";\n    import { openDatabaseSync } from 'expo-sqlite';\n    \n    export const DATABASE_NAME = 'my_db'; \n    \n    export default function RootLayout() {\n      const expoDb = openDatabaseSync(DATABASE_NAME);\n    \n      return \u003cStack /\u003e;\n    }\n    ```\n    \n2. Plug this db instance to drizzle\n    \n    ```jsx\n    // _layout.tsx\n    \n    import { drizzle } from 'drizzle-orm/expo-sqlite';\n    import { Stack } from \"expo-router\";\n    import { openDatabaseSync } from 'expo-sqlite';\n    \n    export const DATABASE_NAME = 'my_db';\n    \n    export default function RootLayout() {\n      const expoDb = openDatabaseSync(DATABASE_NAME);\n      const db = drizzle(expoDb); // connect sqlite db intance to drizzle\n    \n      return \u003cStack /\u003e;\n    }\n    \n    ```\n    \n3. Import the migrations which were generated using drizzle-kit and and execute the migrations using the useMigrations hook.\n    \n    ```jsx\n    // _layout.tsx\n    \n    import migrations from '@/drizzle/migrations'; // import migrations generated using drizzle kit\n    import { drizzle } from 'drizzle-orm/expo-sqlite';\n    import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator'; // hook needed to execute migrations at run time\n    import { Stack } from \"expo-router\";\n    import { openDatabaseSync } from 'expo-sqlite';\n    \n    export const DATABASE_NAME = 'my_db';\n    \n    export default function RootLayout() {\n      const expoDb = openDatabaseSync(DATABASE_NAME);\n      const db = drizzle(expoDb);\n      const { success, error } = useMigrations(db, migrations); // snippet to execute migrations at run time\n    \t\n    \tif (error) console.error(\"Migration error\", error);\n      if (success) console.log(\"Migration success\");\n    \n      return \u003cStack /\u003e;\n    }\n    \n    ```\n    \n4. Provide access to the DB to your entire app using SQLIteProvider\n    \n    ```jsx\n    import migrations from '@/drizzle/migrations';\n    import { drizzle } from 'drizzle-orm/expo-sqlite';\n    import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator';\n    import { Stack } from \"expo-router\";\n    import { openDatabaseSync, SQLiteProvider } from 'expo-sqlite';\n    \n    export const DATABASE_NAME = 'my_db';\n    \n    export default function RootLayout() {\n      const expoDb = openDatabaseSync(DATABASE_NAME);\n      const db = drizzle(expoDb);\n      const { success, error } = useMigrations(db, migrations);\n      \n      if (error) console.error(\"Migration error\", error);\n      if (success) console.log(\"Migration success\");\n    \n      return (\n        \u003cSQLiteProvider\n          databaseName={DATABASE_NAME}\n          options={{ enableChangeListener: true }}\n        \u003e\n          \u003cStack /\u003e\n        \u003c/SQLiteProvider\u003e\n      );\n    }\n    ```\n    \n5. Apply suspense\n    \n    ```jsx\n    import migrations from '@/drizzle/migrations';\n    import { drizzle } from 'drizzle-orm/expo-sqlite';\n    import { useMigrations } from 'drizzle-orm/expo-sqlite/migrator';\n    import { Stack } from \"expo-router\";\n    import { openDatabaseSync, SQLiteProvider } from 'expo-sqlite';\n    import { Suspense } from 'react';\n    import { ActivityIndicator } from 'react-native';\n    \n    export const DATABASE_NAME = 'my_db';\n    \n    export default function RootLayout() {\n      const expoDb = openDatabaseSync(DATABASE_NAME);\n      const db = drizzle(expoDb);\n      const { success, error } = useMigrations(db, migrations);\n      \n      if (error) console.error(\"Migration error\", error);\n      if (success) console.log(\"Migration success\");\n    \n      return (\n        \u003cSuspense fallback={\u003cActivityIndicator size=\"large\" /\u003e}\u003e\n          \u003cSQLiteProvider\n            databaseName={DATABASE_NAME}\n            options={{ enableChangeListener: true }}\n          \u003e\n            \u003cStack /\u003e\n          \u003c/SQLiteProvider\u003e\n        \u003c/Suspense\u003e\n      );\n    }\n    ```\n    \n\n### Make a custom hook that can be used to get the drizzle connection anywhere in your app\n\n1. Make `/src/hooks/drizzleConnection.ts`\n    \n    ```jsx\n    import { drizzle } from \"drizzle-orm/expo-sqlite\";\n    import { useSQLiteContext } from \"expo-sqlite\";\n    import * as schema from \"../db/schema\";\n    \n    export function useDrizzle() {\n      const expoDb = useSQLiteContext();\n      return drizzle(expoDb, { schema });\n    }\n    ```\n    \n2. To use this hook\n    \n    ```jsx\n    // index.tsx\n    \n    import { Text, View } from \"react-native\";\n    import { useDrizzle } from \"../hooks/drizzlleConnection\"; // imported the hook\n    \n    export default function Index() {\n      const db = useDrizzle(); // used the hook to get connection\n    \n      return (\n        \u003cView\n          style={{\n            flex: 1,\n            justifyContent: \"center\",\n            alignItems: \"center\",\n          }}\n        \u003e\n          \u003cText\u003etext\u003c/Text\u003e\n        \u003c/View\u003e\n      );\n    }\n    \n    ```\n    \n\n### Querying the database\n\nWe can use LiveQuery to query the db\n\nExample snippet:\n\n```jsx\nimport { useLiveQuery } from \"drizzle-orm/expo-sqlite\";\nimport { Text, View } from \"react-native\";\nimport { users } from \"../db/schema\"; // import users table schema to query users table\nimport { useDrizzle } from \"../hooks/drizzlleConnection\";\n\nexport default function Index() {\n  const db = useDrizzle();\n  const { data } = useLiveQuery(db.select().from(users)); // the query\n\n  return (\n    \u003cView\n      style={{\n        flex: 1,\n        justifyContent: \"center\",\n        alignItems: \"center\",\n      }}\n    \u003e\n      \u003cText\u003e{JSON.stringify(data)}\u003c/Text\u003e\n    \u003c/View\u003e\n  );\n}\n\n```\n\n### Bonus: Drizzle Studio\n\n---\n\nReferences:\n\n- https://expo.dev/blog/modern-sqlite-for-react-native-apps\n- https://docs.expo.dev/guides/customizing-metro/\n- https://orm.drizzle.team/docs/connect-expo-sqlite\n- https://orm.drizzle.team/docs/latest-releases/drizzle-orm-v0311#live-queries-\n- https://youtu.be/AT5asDD3u_A?si=c3OXtJeOTHsK1fSc\n- https://orm.drizzle.team/docs/get-started/expo-new\n- https://docs.expo.dev/versions/latest/sdk/sqlite/","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebintellectual%2Fdrizzle-expo-setup-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebintellectual%2Fdrizzle-expo-setup-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebintellectual%2Fdrizzle-expo-setup-example/lists"}