Skip to main content

Introduction

New Expensify uses React Native Onyx, a custom state management library built specifically for offline-first applications. Onyx provides automatic persistence, optimistic updates, and conflict resolution out of the box.

Why Onyx?

Traditional state management solutions like Redux or MobX weren’t designed for offline-first apps. Onyx solves unique challenges:
  • Automatic Persistence: All data is automatically saved to disk
  • Optimistic Updates: UI updates immediately, syncs later
  • Conflict Resolution: Built-in strategies for handling sync conflicts
  • Performance: Batched updates and selective re-renders
  • Type Safety: Full TypeScript support

Core Concepts

1. Onyx Keys

All data in Onyx is stored with unique keys defined in src/ONYXKEYS.ts:

2. Onyx Methods

Reading Data with connect

Writing Data

3. Using Onyx with React

Use the useOnyx hook (recommended):
With selectors for performance:

4. Collection Keys

Collections store multiple related items:

Onyx Updates in API Calls

API calls use Onyx updates to manage state:

Onyx Method Types

ONYXKEYS Reference

From src/ONYXKEYS.ts:

Authentication & Session

User Data

Reports & Messages

Transactions

Policies (Workspaces)

Network & App State

Performance Optimization

1. Use Selectors

Selectors prevent unnecessary re-renders:

2. Allow Stale Data

For performance-critical components:

3. Batch Updates

Onyx automatically batches updates, but you can optimize further:

4. Metadata Pattern

Separate loading states from data to prevent re-renders:

Offline Behavior

Pending Actions

Use pendingAction to indicate data state:
UI components can then show pending state:

Error Handling

Store errors in Onyx:
Display errors with OfflineWithFeedback:

Testing with Onyx

Setup

Testing Components

Testing Actions

Best Practices

1. Always Use Typed Keys

2. Clean Up Connections

3. Use Appropriate Merge vs Set

4. Provide All Three Data Sets

For write operations, always include optimistic, success, and failure data:

5. Use finallyData When Appropriate

If success and failure data are identical:

Advanced Patterns

Derived Data

Compute derived values outside Onyx:

Conditional Subscriptions

Debugging Onyx

Redux DevTools Integration

Enable in .env:
Then view Onyx state in Redux DevTools browser extension.

Logging Onyx Changes

Troubleshooting

Data Not Updating

  1. Check that you’re using the correct Onyx key
  2. Verify optimisticData/successData/failureData are set correctly
  3. Check network tab for API responses
  4. Look for errors in failureData being applied

Performance Issues

  1. Use selectors to prevent unnecessary re-renders
  2. Use allowStaleData for non-critical data
  3. Separate data and metadata into different keys
  4. Check for missing React.memo on components

Next Steps

Offline-First

Learn offline-first patterns with Onyx

API Reference

Understand API integration with Onyx

Testing

Test components using Onyx

Best Practices

Follow Onyx best practices