---
description: Learn how configure React Native with Expo to use Triplit in your mobile app.
---

import { Tabs, Tab, Callout } from 'nextra-theme-docs';

# React Native

React Native is the best way to run Triplit on a mobile app. The hooks available in the [React package](/frameworks/react) are also available in React Native.

## Expo

If you are using Expo to setup your React Native project, you can follow these steps to get Triplit up and running.

### 1. Create an Expo project and install Triplit

Create your expo project:

```bash
npx create-expo-app -t expo-template-blank-typescript

cd my-app
```

For more information on setting up an Expo project with typescript see the [Expo documentation](https://docs.expo.dev/guides/typescript/).

Next, install Triplit's packages:

<Tabs items={['npm', 'pnpm', 'yarn', 'bun']}>
  <Tab>
    ```bash
    npm i @triplit/client @triplit/react
    npm i @triplit/cli --save-dev
    ```
  </Tab>
  <Tab>
    ```bash
    pnpm add @triplit/client @triplit/react
    pnpm add @triplit/cli --save-dev
    ```

  </Tab>
  <Tab>
    ```bash
    yarn add @triplit/client @triplit/react
    yarn add @triplit/cli --dev
    ```

  </Tab>
  <Tab>
    ```bash
    bun add @triplit/client @triplit/react
    bun add @triplit/cli --dev
    ```
    
    </Tab>
</Tabs>

### 2. Update metro.config.js

Some Triplit packages use [Package Exports](https://nodejs.org/docs/latest-v18.x/api/packages.html#package-entry-points), which Metro does not yet support.

<Callout type="info" emoji="ℹ️">
  Metro does have a configuration option
  [unstable_enablePackageExports](https://metrobundler.dev/docs/configuration/#unstable_enablepackageexports-experimental)
  but we found it broke other parts of the package resolution process.
</Callout>

To handle these imports, you will need to customize the Metro bundler. If you have not already created a `metro.config.js` file, please see the Expo docs on properly [configuring Metro](https://docs.expo.dev/guides/customizing-metro/). Once you have created a `metro.config.js` file, you can add the following code to resolve the exports from the Triplit packages:

```javascript
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');
const config = getDefaultConfig(__dirname);

// additional configuration steps

// Resolve exports for these Triplit packages
const packageExportsDependencies = ['@triplit/db', '@triplit/tuple-database'];
// Custom resolver function
function customResolver(context, moduleName, platform) {
  for (const dep of packageExportsDependencies) {
    const prefix = dep + '/';
    if (moduleName.startsWith(prefix)) {
      const suffix = moduleName.replace(prefix, '');
      const basePath = path.dirname(require.resolve(dep));
      const filePath = path.join(basePath, `${suffix}.js`);
      return {
        filePath: filePath,
        type: 'sourceFile',
      };
    }
  }
  return context.resolveRequest(context, moduleName, platform);
}
config.resolver.resolveRequest = customResolver;

module.exports = config;
```

### 3. Configure Babel (optional)

If you are building for the web, you'll need to update a babel configuration file. At the root of your Expo project, create a `babel.config.js` file with the following content:

```javascript
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    assumptions: {
      enumerableModuleMeta: true,
    },
  };
};
```

### 4. Configure polyfills

Triplit was originally built to run in web browsers, so a few APIs are used in some core packages and dependencies that are not in the ECMAScript spec that Hermes implements. So you will need to add some polyfills to your project. We list some polyfills below, but you may use other packages or write your own.

- crypto.getRandomValues: [react-native-get-random-values](https://www.npmjs.com/package/react-native-get-random-values)
- URL: [react-native-url-polyfill](https://www.npmjs.com/package/react-native-url-polyfill)
- atob / btoa: [@react-native-anywhere/polyfill-base64](https://www.npmjs.com/package/@react-native-anywhere/polyfill-base64)
- EventTarget: [event-target-polyfill](https://www.npmjs.com/package/event-target-polyfill)
- hasown: [hasown](https://www.npmjs.com/package/hasown)
- AsyncIterator: [@azure/core-asynciterator-polyfill](https://www.npmjs.com/package/@azure/core-asynciterator-polyfill)

These polyfills should be imported or implemented in your project's entry file so they can be run as early as possible. Typically this is your `index.js` file. If you are using Expo Router see this [thread](https://github.com/expo/expo/discussions/25122) on creating and using an `index.js` file to add polyfills.

```javascript
import 'react-native-get-random-values';
import 'react-native-url-polyfill/auto';
import '@react-native-anywhere/polyfill-base64';
import 'event-target-polyfill';
import 'hasown';
import '@azure/core-asynciterator-polyfill';
// ... other polyfills

// If using Expo Router:
import 'expo-router/entry';

// The rest of your entry file
```

### Local development

When running a local development server on your machine, it will be running at `localhost`. However if you are running your app on a physical device (ie your phone with the Expo Go app or a custom build) you will need to change the `localhost` to your machine's IP address. You can find your IP address by running `ipconfig getifaddr en0` in your terminal. So a URL `http://localhost:<port>` would become `http://<your-ip>:<port>`.

## Storage providers

Triplit provides storage providers for React Native applications to persist data on the device, including for `expo-sqlite`. Read more about the available storage providers in the [client storage documentation](/client/storage#in-react-native).

## Bare React Native

The team over at Triplit hasn't had the chance to test out a bare React Native project. Although we don't expect the required steps to be much different than with Expo, there may be differences. If you have set up Triplit in a bare RN project, please let us know how it went!
