Skip to main content
The configureObservableSync() function sets global defaults for all synced observables. This is useful for setting application-wide persistence plugins, retry behavior, and other common settings.

Usage

import { configureObservableSync } from '@legendapp/state/sync'
import { ObservablePersistLocalStorage } from '@legendapp/state/persist-plugins/local-storage'

configureObservableSync({
  persist: {
    plugin: ObservablePersistLocalStorage
  },
  retry: {
    infinite: true,
    delay: 1000
  },
  debounceSet: 500
})

Parameters

options
SyncedOptionsGlobal
required
Global configuration options for all synced observables

SyncedOptionsGlobal

persist
PersistOptions
Default persistence configuration
retry
RetryOptions
Default retry behavior for failed operations
debounceSet
number
Default debounce time in milliseconds for remote saves. Batches rapid changes together.
debounceSet: 500  // Wait 500ms after last change before saving
syncMode
'auto' | 'manual'
default:"auto"
Default sync mode for all observables
  • auto: Sync automatically when accessed
  • manual: Only sync when sync() is called
mode
'set' | 'assign' | 'merge' | 'append' | 'prepend'
default:"set"
Default mode for applying remote data
onBeforeSet
(params: { cancel: boolean }) => void
Global handler called before any set operation
onAfterSet
() => void
Global handler called after any set operation
onError
(error: Error, params: SyncedErrorParams) => void
Global error handler for all sync operations
onError: (error, { source, type, retry, revert }) => {
  console.error(`Error in ${source}:`, error)
  // Report to error tracking service
  Sentry.captureException(error)
}

Return Value

This function does not return a value. It modifies the global configuration.

Examples

Basic Configuration

import { configureObservableSync } from '@legendapp/state/sync'
import { ObservablePersistLocalStorage } from '@legendapp/state/persist-plugins/local-storage'

configureObservableSync({
  persist: {
    plugin: ObservablePersistLocalStorage
  }
})

// Now all synced observables use localStorage by default
const user$ = synced({
  get: () => api.getUser(),
  persist: { name: 'user' }  // No need to specify plugin
})

IndexedDB Configuration

import { configureObservableSync } from '@legendapp/state/sync'
import { ObservablePersistIndexedDB } from '@legendapp/state/persist-plugins/indexeddb'

configureObservableSync({
  persist: {
    plugin: ObservablePersistIndexedDB,
    indexedDB: {
      databaseName: 'myapp',
      version: 1,
      tableNames: ['users', 'posts', 'comments', 'settings']
    }
  }
})

React Native with AsyncStorage

import { configureObservableSync } from '@legendapp/state/sync'
import { ObservablePersistAsyncStorage } from '@legendapp/state/persist-plugins/async-storage'
import AsyncStorage from '@react-native-async-storage/async-storage'

configureObservableSync({
  persist: {
    plugin: ObservablePersistAsyncStorage,
    asyncStorage: {
      AsyncStorage,
      preload: ['user', 'settings']  // Preload specific keys
    }
  }
})

Retry Configuration

configureObservableSync({
  retry: {
    infinite: true,     // Keep retrying
    delay: 1000,        // Start with 1 second
    backoff: 'exponential',  // Double each time
    maxDelay: 30000     // Max 30 seconds between retries
  },
  persist: {
    plugin: ObservablePersistLocalStorage,
    retrySync: true     // Retry failed syncs on next load
  }
})

Debounce Configuration

configureObservableSync({
  debounceSet: 1000,  // Wait 1 second after last change
  persist: {
    plugin: ObservablePersistLocalStorage
  }
})

// Good for rapid user input
const search$ = synced({
  get: (params) => api.search(params.value),
  persist: { name: 'search' }
  // Inherits 1 second debounce
})

Global Error Handling

import * as Sentry from '@sentry/browser'

configureObservableSync({
  persist: {
    plugin: ObservablePersistLocalStorage,
    onGetError: (error) => {
      console.error('Persistence load error:', error)
      Sentry.captureException(error)
    },
    onSetError: (error) => {
      console.error('Persistence save error:', error)
      Sentry.captureException(error)
    }
  },
  onError: (error, { source, type }) => {
    console.error(`Sync error in ${source} (${type}):`, error)
    Sentry.captureException(error, {
      tags: { source, type }
    })
  }
})

Manual Sync Mode

configureObservableSync({
  syncMode: 'manual',  // Don't sync automatically
  persist: {
    plugin: ObservablePersistLocalStorage
  }
})

// All observables now require manual sync
const data$ = synced({
  get: () => api.getData(),
  persist: { name: 'data' }
})

// Must call sync manually
const syncState = syncState(data$)
await syncState.sync()

Offline-First Configuration

configureObservableSync({
  persist: {
    plugin: ObservablePersistIndexedDB,
    retrySync: true,  // Queue failed syncs
    indexedDB: {
      databaseName: 'myapp_offline',
      version: 1,
      tableNames: ['todos', 'notes']
    }
  },
  retry: {
    infinite: true,  // Keep trying to sync
    delay: 5000,     // Try every 5 seconds
    backoff: 'constant'
  },
  debounceSet: 2000,  // Batch changes
  onError: (error, { source }) => {
    // Don't show errors for network failures
    if (error.message.includes('fetch')) return
    showErrorToast(`${source} failed: ${error.message}`)
  }
})

Per-Observable Override

Individual observables can override global settings:
// Global config
configureObservableSync({
  debounceSet: 500,
  retry: { times: 3 }
})

// Override for specific observable
const data$ = synced({
  get: () => api.getData(),
  debounceSet: 0,  // No debounce for this one
  retry: { infinite: true }  // Retry forever
})

Best Practices

  1. Call early: Configure before creating any synced observables
  2. Use appropriate plugin: localStorage for web, AsyncStorage/MMKV for React Native
  3. Enable retry: Use retrySync: true for offline support
  4. Set debounce: Use debounceSet to reduce server load
  5. Handle errors: Implement onError for production apps

See Also

Build docs developers (and LLMs) love