# React Native

Connect a React Native app to SurrealDB and run your first queries.

[React Native](https://reactnative.dev/) builds Android and iOS apps from React components. This guide connects a React Native app to SurrealDB, writes a few records, and shows them on screen.

When you finish, you will have a screen that lists records read from your database.

## Before you begin

You need two things:

- A React Native project on 0.79 or newer, created with `npx @react-native-community/cli init`
- A running [SurrealDB instance](/docs/running/overview.md) on your development machine

A mobile app cannot run SurrealDB on the device itself, so it always talks to a database over the network.

> [!NOTE]
> Using [Expo](/docs/frameworks/expo.md)? Follow that guide instead. Expo already provides the browser APIs installed in step 1.

## 1. Install the SDK and its polyfills

React Native's JavaScript engine leaves out two browser APIs that the SDK needs: `TextDecoder`, used to read responses from the database, and a complete `URL`, used to parse the address you connect to. Install them alongside the SDK.

```bash
npm install --save surrealdb @bacons/text-decoder react-native-url-polyfill
```

Import both at the very top of `index.js`, above every other import. They have to be in place before the SDK is loaded.

```js title="index.js"
import "react-native-url-polyfill/auto";
import "@bacons/text-decoder/install";

import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);
```

Both packages are plain JavaScript, so there is nothing to rebuild.

## 2. Create the database client

Create a file that holds a single `Surreal` client and the function that opens the connection. Keeping both in one module means every screen shares the same connection.

```ts title="surreal.ts"
import { Surreal } from "surrealdb";

export const db = new Surreal();

export function connectToSurreal() {
    return db.connect("ws://10.0.2.2:8000", {
        namespace: "example",
        database: "getting_started",
        authentication: {
            username: "root",
            password: "root",
        },
    });
}
```

`.connect()` takes the address of your database, along with the [namespace and database](/docs/learn/data-models.md) to work in and the credentials to sign in with. Use `ws://` or `wss://` addresses: a WebSocket connection stays open, so the app authenticates once instead of on every request.

### Setting the address

On a phone or emulator, `localhost` means the device itself, not your development machine. Use the address that the device can actually reach.

| Where the app runs | Address to use |
|--------------------|----------------|
| iOS simulator | `ws://127.0.0.1:8000` |
| Android emulator | `ws://10.0.2.2:8000` |
| Physical device | `ws://<your-machine-lan-ip>:8000` |

A new React Native project already permits unencrypted local connections while you develop, so `ws://` works without any further setup. Release builds do not, which is why production apps connect over `wss://`.

> [!WARNING]
> The `root` credentials above are for a local database you are experimenting with. Everything you compile into a mobile app is readable by anyone who installs it, so a released app must never carry them. Use [record access](/docs/reference/query-language/statements/define/access/record.md) to sign real users in instead.

## 3. Connect when the app starts

Open the connection in `App.tsx` and wait for it before showing the rest of the app, so no screen queries a connection that is not ready.

```tsx title="App.tsx"
import React, { useEffect, useState } from "react";
import { ActivityIndicator, Text } from "react-native";
import { connectToSurreal } from "./surreal";
import { ProductList } from "./ProductList";

export default function App() {
    const [status, setStatus] = useState<"connecting" | "ready" | "failed">("connecting");

    useEffect(() => {
        connectToSurreal()
            .then(() => setStatus("ready"))
            .catch(() => setStatus("failed"));
    }, []);

    if (status === "connecting") return <ActivityIndicator />;
    if (status === "failed") return <Text>Could not reach the database.</Text>;

    return <ProductList />;
}
```

If you see the failure message, the address is usually the cause. Check the table in step 2 and confirm that SurrealDB is running.

## 4. Insert your first records

Use `.create()` to add a record to a table. The `.content()` chain holds the fields you want to store.

```ts
import { RecordId, Table } from "surrealdb";
import { db } from "./surreal";

const products = new Table("products");

// Create a record with an ID generated by the database
const [banana] = await db.create(products).content({
    name: "Banana",
    price: 0.8,
});

console.log(banana);
// { id: products:0dxay1r0dc9c1cn8vzuq, name: 'Banana', price: 0.8 }

// Create a record with an ID you choose
const apple = await db.create(new RecordId(products, "apple")).content({
    name: "Apple",
    price: 1.5,
});

console.log(apple);
// { id: products:apple, name: 'Apple', price: 1.5 }
```

Every record has an ID made of its table name and a unique key, written as `products:apple`. You do not need to create the table first - SurrealDB adds it on the first write.

## 5. Read and display data

`.select()` reads records back. Pass a `Table` to read all of them, or a `RecordId` to read one. Chain `.where()` and `.limit()` to narrow the result.

```tsx title="ProductList.tsx"
import React, { useEffect, useState } from "react";
import { FlatList, Text, View } from "react-native";
import { Table, lt } from "surrealdb";
import { db } from "./surreal";

interface Product {
    id: string;
    name: string;
    price: number;
}

export function ProductList() {
    const [products, setProducts] = useState<Product[]>([]);

    useEffect(() => {
        db.select<Product>(new Table("products"))
            .where(lt("price", 1.0))
            .then(setProducts)
            .catch(console.error);
    }, []);

    return (
        <FlatList
            data={products}
            keyExtractor={(product) => String(product.id)}
            renderItem={({ item }) => (
                <View>
                    <Text>{item.name}</Text>
                    <Text>{item.price}</Text>
                </View>
            )}
        />
    );
}
```

`lt` is one of the [expression helpers](/docs/reference/javascript/api/utilities/expr.md) the SDK provides for building conditions. Run the app and you should see the products you created.

## Next steps

You now have a React Native app that connects to SurrealDB, writes records, and reads them back. Real apps also need to sign users in, keep working when the phone locks the screen, and react to changes as they happen.

- [React Native SDK guide](/docs/reference/javascript/frameworks/react-native.md) - The full integration guide: connection provider, app lifecycle, secure token storage, and live queries.

- [Authentication](/docs/reference/javascript/concepts/authentication.md) - Sign users up and in with record access instead of database credentials.

- [Executing queries](/docs/reference/javascript/concepts/executing-queries.md) - Learn the query builders and how to run SurrealQL statements directly.

- [Live queries](/docs/reference/javascript/concepts/live-queries.md) - Receive changes from the database as they happen, without polling.
