Flagdeck
Pricing
Docs
Get Started

Docs

Docs


SDKs

  • JavaScript
    • Getting Started
    • Value Types
    • Evaluation Context
    • Configuration
    • Real Time Updates
    • Error Handling
    • Middleware
    • Offline Mode
    • API Reference
  • React

API Reference

  • Authentication
  • Flags
  • Environments
  • Projects

Offline Mode

Offline mode allows your application to continue evaluating feature flags even when the network is unavailable. This is especially important for mobile applications, applications that work offline, or when you want to ensure consistent user experiences during connectivity issues.

Benefits of Offline Mode

  • Resilience to Network Issues: Maintain functionality during temporary outages
  • Improved Performance: Reduce latency by avoiding network requests
  • Reduced Server Load: Decrease the number of API calls to your flag evaluation endpoints
  • Consistent Experience: Prevent feature flickering during connectivity fluctuations
  • Critical for Mobile: Essential for mobile apps operating in low/no connectivity environments

Enabling Offline Mode

Offline mode is disabled by default. To enable it, set the enableOfflineMode option to true when initializing the Flagdeck client:

import { Flagdeck } from '@flagdeck/js';

const flagdeck = new Flagdeck({
  apiKey: 'your-api-key',
  enableOfflineMode: true
});

How Offline Mode Works

With offline mode enabled, the SDK:

  1. Stores flag values locally when they are successfully evaluated
  2. Uses stored values if a network error occurs during evaluation
  3. Automatically handles transitions between online and offline states
  4. Manages storage limits and performs automatic cleanup
  5. Handles flag expiration to ensure stale values aren't used indefinitely

The process is entirely transparent to your application code. Flag evaluations behave the same way regardless of connectivity state.

Storage Implementation

The SDK uses an optimized storage system with the following features:

  • Efficient Storage: Minimizes disk/memory usage with JSON serialization
  • Automatic Pruning: Oldest flags are removed when storage limits are reached
  • Size Management: Storage size is monitored (100KB limit in browsers, 500KB in Node.js)
  • Flag Expiration: Flags automatically expire after 7 days by default
  • Intelligent Cache: In-memory caching for fast access with persistent backing

Storage Mechanisms

The SDK automatically selects the appropriate storage mechanism based on the environment:

  • Browser: Uses localStorage with memory fallback
  • Node.js: Uses filesystem storage in the user's home directory (~/.flagdeck) with temp directory fallback
  • React Native: Uses AsyncStorage when available

Manual Control of Offline Storage

Saving Flags for Offline Use

You can manually save flag values for offline use:

// Save a single flag
await flagdeck.saveForOffline('feature-a', true);

// Save multiple flags at once
await flagdeck.saveMultipleForOffline({
  'feature-a': true,
  'feature-b': false,
  'limit': 100
});

Clearing Offline Storage

To clear all stored flags:

await flagdeck.clearOfflineStorage();

Bootstrapping Offline Values

A common pattern is to bootstrap your application with a set of offline values at startup:

async function initializeFlagdeck(userContext) {
  // Create the client
  const flagdeck = new Flagdeck({
    apiKey: 'your-api-key',
    enableOfflineMode: true
  });

  try {
    // Fetch all flags needed by your application
    const values = await flagdeck.getValues([
      'feature-a',
      'feature-b',
      'limit-value',
      'experiment-variant'
    ], userContext);

    // Save for offline use
    await flagdeck.saveMultipleForOffline(values);

    console.log('Flags bootstrapped for offline use');
  } catch (error) {
    console.error('Failed to bootstrap flags:', error);
    // Application can still proceed - existing offline values will be used if available
  }

  return flagdeck;
}

// Usage
const flagdeck = await initializeFlagdeck(userContext);

Flushing Before App Closure

For browser applications, it's important to flush storage and analytics before the app closes:

// Ensure flags are properly saved and analytics are sent before app closes
window.addEventListener('beforeunload', async () => {
  // Save important flags
  await flagdeck.saveMultipleForOffline({
    'critical-feature': await flagdeck.getValue('critical-feature'),
    'user-settings': await flagdeck.getValue('user-settings')
  });
  
  // Flush analytics
  await flagdeck.flushAnalytics();
});

Storage Management and Limits

The SDK includes built-in storage management to handle limits efficiently:

  • Automatic Expiration: Flags expire after 7 days by default
  • Storage Caps: 100KB limit in browsers, 500KB in Node.js
  • Count Limits: Maximum of 100 flags stored by default
  • Oldest-First Removal: When limits are reached, oldest flags are removed first
  • Size-Based Pruning: Intelligent size management when approaching limits

These limits help prevent storage issues, especially in browser environments with strict localStorage quotas.

Best Practices for Offline Mode

1. Always Include Default Values

Even with offline mode, always provide default values for critical flags:

// Default value will be used if both network and offline storage fail
const limit = await flagdeck.getValue('api-rate-limit', context, 50);

2. Periodic Synchronization

For applications that run for extended periods offline, implement periodic synchronization:

async function synchronizeFlags(userContext) {
  try {
    // Get the latest values for critical flags
    const values = await flagdeck.getValues([
      'feature-a',
      'feature-b',
      'config-value'
    ], userContext);
    
    // Save for offline use
    await flagdeck.saveMultipleForOffline(values);

    console.log('Flags synchronized successfully');
  } catch (error) {
    console.warn('Could not synchronize flags:', error);
  }
}

// Call when the application comes online
networkStatusMonitor.onConnectionRestored(() => {
  synchronizeFlags(currentUserContext);
});

// Or on a periodic schedule when online
setInterval(() => {
  if (navigator.onLine) {
    synchronizeFlags(currentUserContext);
  }
}, 60 * 60 * 1000); // Every hour

3. Prioritize Critical Flags

With storage limits, prioritize saving your most critical flags:

// Identify critical flags that should always be saved
const CRITICAL_FLAGS = [
  'payment-gateway',
  'auth-method',
  'critical-config'
];

// Save critical flags first
async function saveOfflinePriorities(context) {
  const criticalValues = await flagdeck.getValues(CRITICAL_FLAGS, context);
  await flagdeck.saveMultipleForOffline(criticalValues);
}

4. Monitor Offline Usage

Track when offline values are being used:

flagdeck.use({
  name: 'OfflineMonitoring',
  afterEvaluation: (flagKey, result, context) => {
    if (result.source === 'offline') {
      // Log or track offline usage
      analytics.track('Flag Offline Usage', {
        flagKey,
        value: result.value,
        timestamp: Date.now()
      });
    }
    return result;
  }
});

Handling Different Result Sources

When offline mode is enabled, flag evaluation results include a source property that indicates where the value came from:

const result = await flagdeck.evaluateFlag('new-feature');

switch (result.source) {
  case 'api':
    // Value came directly from the API
    console.log('Using latest value from API');
    break;

  case 'cache':
    // Value came from in-memory cache
    console.log('Using cached value');
    break;

  case 'offline':
    // Value came from offline storage due to network error
    console.log('Using offline stored value due to network error');
    // You might want to show a subtle indicator that the app is working offline
    showOfflineIndicator();
    break;

  case 'error':
    // Error occurred and no offline value was available
    console.log('Using default value due to error');
    break;
}

Troubleshooting Offline Mode

If you're experiencing issues with offline mode:

1. Enable Debug Mode

Enable debugging for detailed logs:

const flagdeck = new Flagdeck({
  apiKey: 'your-api-key',
  enableOfflineMode: true,
  debug: true
});

2. Check Storage Availability

// Check if storage is available in browser
function isStorageAvailable() {
  try {
    const test = '__storage_test__';
    localStorage.setItem(test, test);
    localStorage.removeItem(test);
    return true;
  } catch (e) {
    return false;
  }
}

console.log('Storage available:', isStorageAvailable());

3. Add Debugging Middleware

flagdeck.use({
  name: 'OfflineDebugger',
  afterEvaluation: (flagKey, result, context) => {
    console.log(`Flag ${flagKey} evaluation:`, {
      value: result.value,
      source: result.source,
      timestamp: new Date(result.timestamp).toISOString()
    });
    return result;
  }
});

Environment-Specific Considerations

Browser Environment

  • Storage Quota: Be mindful of localStorage quotas (typically 5-10MB per domain)
  • Incognito Mode: localStorage may be limited or unavailable
  • Flushing: Call flushAnalytics() before page unloads

Node.js Environment

  • Storage Location: Flags are stored in ~/.flagdeck/ (home directory)
  • File Permissions: Ensure write permissions to the storage directory
  • Multiple Processes: Each process maintains its own copy of offline storage

React Native

  • AsyncStorage: Ensure AsyncStorage is properly installed and available
  • Storage Permissions: Verify storage permissions on the device
  • Memory Usage: Monitor memory usage, especially on low-end devices

Real-World Example: React Application

Here's how you might integrate offline mode in a React application:

import React, { useState, useEffect } from 'react';
import { Flagdeck } from '@flagdeck/js';

// Create the client at the app level
const flagdeck = new Flagdeck({
  apiKey: 'your-api-key',
  enableOfflineMode: true,
  debug: process.env.NODE_ENV !== 'production'
});

// Bootstrap offline flags at startup
useEffect(() => {
  async function bootstrapFlags() {
    try {
      const criticalFlags = await flagdeck.getValues([
        'new-feature',
        'experiment-variant',
        'api-config',
      ], userContext);
      
      await flagdeck.saveMultipleForOffline(criticalFlags);
      console.log('Critical flags bootstrapped for offline use');
    } catch (error) {
      console.warn('Failed to bootstrap flags:', error);
    }
  }
  
  bootstrapFlags();
  
  // Flush analytics and important flags on unmount
  return () => {
    flagdeck.flushAnalytics().catch(err => {
      console.warn('Failed to flush analytics:', err);
    });
  };
}, []);

// Custom hook for feature flags with offline support
function useFeatureFlag(flagKey, defaultValue, context) {
  const [value, setValue] = useState(defaultValue);
  const [loading, setLoading] = useState(true);
  const [source, setSource] = useState(null);

  useEffect(() => {
    let isMounted = true;

    async function checkFlag() {
      try {
        setLoading(true);
        const result = await flagdeck.evaluateFlag(flagKey, context);

        if (isMounted) {
          setValue(result.value);
          setSource(result.source);
          
          // Save successful evaluation for future offline use
          if (result.source === 'api' || result.source === 'cache') {
            flagdeck.saveForOffline(flagKey, result.value)
              .catch(err => console.warn('Failed to save for offline:', err));
          }
        }
      } catch (err) {
        console.error(`Error evaluating flag ${flagKey}:`, err);
        // Keep default value
      } finally {
        if (isMounted) {
          setLoading(false);
        }
      }
    }

    checkFlag();
    return () => { isMounted = false; };
  }, [flagKey, JSON.stringify(context)]);

  return { value, loading, source };
}

// Component using feature flag
function FeatureComponent({ user }) {
  const context = {
    userId: user.id,
    attributes: { plan: user.plan, country: user.country }
  };

  const { value: isNewFeatureEnabled, loading, source } = 
    useFeatureFlag('new-feature', false, context);

  // Show offline indicator if using offline storage
  const isOffline = source === 'offline';

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {isOffline && <div className="offline-indicator">Using offline data</div>}
      {isNewFeatureEnabled ? <NewFeatureComponent /> : <OldFeatureComponent />}
    </div>
  );
}

Conclusion

Offline mode in Flagdeck provides robust feature flag evaluation in any network condition. The implementation includes automatic storage management, flag expiration, and efficient pruning to ensure optimal performance.

Key takeaways:

  1. Enable offline mode for resilient applications
  2. Bootstrap critical flags at startup
  3. Provide sensible defaults as fallbacks
  4. Be aware of storage limits (100KB browser, 500KB Node.js, 100 flags)
  5. Flush before app closure for guaranteed persistence
  6. Implement periodic synchronization for long-running applications

With these strategies, your application can provide a consistent experience regardless of network conditions while ensuring efficient storage usage.

Start using Flagdeck today

Simple feature flag management for modern development teams.

Get Started
Flagdeck

Modern feature flag management platform to help you deploy with confidence.

Product

FeaturesPricingDocumentation

© 2025 Flagdeck. All rights reserved.