Expo

For Expo and React Native apps, FFDB setup centers on three choices: how you load the API URL, how you persist auth/session state, and whether you enable offline sync with local SQLite.

Why Expo setup differs from web

  • Name
    Different public env key
    Description

    Expo apps use EXPO_PUBLIC_FFDB_API_URL.

  • Name
    Custom persistence requirements
    Description

    Mobile apps usually need explicit storage adapters for restart-safe sessions.

  • Name
    Runtime-specific offline wiring
    Description

    Offline adapter and network adapter integration often differ from browser defaults.

CLI scaffold path

Use the CLI when starting from scratch:

ffdb-cli init

Recommended prompts for Expo:

  1. Platform: Expo / React Native
  2. Optional offline support: expo-sqlite
  3. Env setup: writes EXPO_PUBLIC_FFDB_API_URL and FFDB_AUTH_TOKEN

Core setup in app code

import { createClient } from 'ffdb-client'
import type { Database } from './ffdb.types'

const client = await createClient<Database>({
  config: {
    apiUrl: process.env.EXPO_PUBLIC_FFDB_API_URL,
  },
  storage: mobileStorageAdapter,
})

const { db, auth, sync } = client

Storage adapter contract (mobile)

type StorageAdapter = {
  get(key: string): Promise<string | null> | string | null
  set(key: string, value: string): Promise<void> | void
  remove(key: string): Promise<void> | void
}

Example wrapper (conceptual) for AsyncStorage or secure store:

const mobileStorageAdapter = {
  get: async (key: string) => await myStorage.getItem(key),
  set: async (key: string, value: string) => await myStorage.setItem(key, value),
  remove: async (key: string) => await myStorage.removeItem(key),
}

Offline adapter + network adapter (optional)

type OfflineAdapter = {
  execute(sql: string, params?: unknown[]): Promise<{ rows: Record<string, unknown>[] }> | { rows: Record<string, unknown>[] }
}

type NetworkAdapter = {
  isOnline(): boolean | Promise<boolean>
  subscribe(listener: (online: boolean) => void): () => void
}

Typical Expo pattern:

const { sync } = await createClient<Database>({
  config: { apiUrl: process.env.EXPO_PUBLIC_FFDB_API_URL },
  storage: mobileStorageAdapter,
  offline: {
    adapter: expoSqliteAdapter,
    network: netInfoAdapter,
    syncOnReconnect: true,
    syncOnFocus: false,
  },
})

await sync?.run()

Practical guidance

  1. Prefer explicit storage adapters so auth/session state survives app restarts.
  2. Use offline mode only when your product actually needs disconnected writes.
  3. Keep sync triggers conservative on mobile to balance freshness vs battery/network cost.
  4. Surface online/offline and pending mutation state in UI.

Next pages

  1. Node.js
  2. Electron
  3. Reference: createClient

Was this page helpful?