Aurabase Logo
aurabasedocs
docs›Guides›Expo / React Native

Use Aurabase in an Expo / React Native app

Create the client with EXPO_PUBLIC_* variables, keep the session across app restarts, and subscribe to database changes.

5 min read·Level intermediate·Revised on Oct 22, 2026
This English text was generated automatically from the French original and has not been reviewed yet.
#
Status

1. What was verified

@aurabase/aurabase-js bundles without error for Android in an Expo project (npx expo export --platform android, Expo SDK 58, React Native 0.88). Running the app on a device or a simulator has not been verified yet: treat the session and realtime examples below as the intended usage, and report anything that differs.

Aurabase has no Flutter or Dart package on pub.dev yet: for Flutter, call the REST API (see REST API).

#
Setup

2. Install and configure

terminalbash
npx expo install expo-secure-store
npm install @aurabase/aurabase-js

Expo exposes to the app only the variables whose name starts with EXPO_PUBLIC_. Put the project URL and the anon key (never the service_role key: it would ship inside the app) in .env:

.envbash
EXPO_PUBLIC_AURABASE_URL=https://<slug>.aurabase.cloud
EXPO_PUBLIC_AURABASE_ANON_KEY=aura_anon_…
#
Session

3. Keep the session

On the web the SDK keeps the session in localStorage; React Native has none. Give the client an auth store that writes the session to expo-secure-store. The store is read at start-up, before the client is created:

lib/aurabase.tstypescript
import * as SecureStore from 'expo-secure-store'
import { BaseAuthStore, createClient } from '@aurabase/aurabase-js'
import type { User } from '@aurabase/aurabase-js'

const KEY = 'aurabase-session'

class SecureStoreAuthStore extends BaseAuthStore {
  override save(token: string, refreshToken: string, user: User): void {
    super.save(token, refreshToken, user)
    void SecureStore.setItemAsync(KEY, JSON.stringify({ token, refreshToken, user }))
  }

  override clear(): void {
    super.clear()
    void SecureStore.deleteItemAsync(KEY)
  }
}

/** Read the saved session once, at app start, before rendering anything that needs it. */
export async function createAuraClient() {
  const store = new SecureStoreAuthStore()
  const saved = await SecureStore.getItemAsync(KEY)
  if (saved) {
    const { token, refreshToken, user } = JSON.parse(saved) as {
      token: string
      refreshToken: string
      user: User
    }
    store.save(token, refreshToken, user)
  }
  return createClient(
    process.env.EXPO_PUBLIC_AURABASE_URL!,
    process.env.EXPO_PUBLIC_AURABASE_ANON_KEY!,
    { auth: { storage: store } },
  )
}
Attention

expo-secure-store limits the size of a value on some devices (about 2 KB). If your session carries a lot of user metadata and save fails, store it with @react-native-async-storage/async-storage instead (less protected) or keep only the tokens.

#
Realtime

4. Realtime

React Native provides a WebSocket, which the SDK uses. A channel opened before the user signs in is re-authenticated when the session changes, so the order of subscribe() and signInWithPassword() does not matter.

components/Todos.tsxtypescript
import { useEffect } from 'react'
import type { AuraClient } from '@aurabase/aurabase-js'

export function useTodoChanges(aura: AuraClient, onChange: (type: string) => void) {
  useEffect(() => {
    const channel = aura.realtime
      .channel('todos')
      .on('postgres_changes', { event: '*', schema: 'public', table: 'todos' }, (change) =>
        onChange(change.eventType),
      )
      .subscribe((status) => {
        if (status === 'CHANNEL_ERROR') console.warn('realtime refused')
      })
    return () => {
      channel.unsubscribe()
    }
  }, [aura, onChange])
}
Last updated · Oct 22, 2026