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:
- Platform: Expo / React Native
- Optional offline support: expo-sqlite
- Env setup: writes
EXPO_PUBLIC_FFDB_API_URLandFFDB_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
- Prefer explicit storage adapters so auth/session state survives app restarts.
- Use offline mode only when your product actually needs disconnected writes.
- Keep sync triggers conservative on mobile to balance freshness vs battery/network cost.
- Surface online/offline and pending mutation state in UI.
Do not place privileged credentials in app-bundled public env values. Keep setup/admin secrets in trusted environments.