Skip to main content

Local Evaluation

Performance

Evaluate feature flags locally for sub-millisecond latency. Cache at the edge, support offline mode, and reduce network calls.

<1ms Evaluation

Local computation, no network

Edge Caching

Flags cached at CDN edge

Offline Support

Works without internet

Auto Sync

Background updates

Client-Side vs Server-Side Evaluation

Choose the right evaluation strategy based on your needs. Each approach has trade-offs between latency, security, and real-time updates.

Server-Side

  • +Secure: rules not exposed to client
  • +Real-time: always latest rules
  • -Latency: network round-trip
  • -Requires: server infrastructure

Client-Side (Local)

  • +Fast: sub-millisecond evaluation
  • +Offline: works without network
  • -Stale: rules may be outdated
  • -Exposed: rules visible to client
// Server-side evaluation (API route, server component)
import { platform } from '@/lib/platform'

export async function GET(request: Request) {
  const user = await getUser(request)

  // Evaluates on server, fetches latest rules
  const isEnabled = await platform.flags.isEnabled('new_feature', {
    userId: user.id,
    context: { plan: user.plan },
  })

  return Response.json({ enabled: isEnabled })
}

When to Use Each

  • Server-side: Access control, billing features, sensitive operations
  • Client-side: UI variations, cosmetic changes, non-sensitive features
  • Hybrid: Most applications - secure where needed, fast everywhere else

Caching Flag Values

Cache flag configurations to reduce latency and network calls. The SDK handles caching automatically with configurable freshness.

Cache Configuration
import { SylphxProvider } from '@sylphx/sdk/react'

function App() {
  return (
    <SylphxProvider
      projectId="proj_xxx"

      // Caching options
      cache={{
        // Where to store cached flags
        storage: 'localStorage', // 'localStorage' | 'sessionStorage' | 'memory'

        // How long until cache is considered stale
        maxAge: 5 * 60 * 1000, // 5 minutes

        // Use stale cache while fetching fresh data
        staleWhileRevalidate: true,

        // Cache key prefix (for multiple projects)
        keyPrefix: 'sylphx_flags_',
      }}
    >
      <MyApp />
    </SylphxProvider>
  )
}

// Manual cache control
import { flagsClient } from '@sylphx/sdk'

// Force refresh cache
await flagsClient.refresh()

// Clear cache
flagsClient.clearCache()

// Get cache status
const status = flagsClient.getCacheStatus()
// { lastUpdated: Date, isStale: boolean, size: 42 }

Cache Levels

Memory (L1)
<0.1ms
Session only
LocalStorage (L2)
<1ms
Persists across sessions
Edge CDN (L3)
~10ms
Shared across users
Origin Server
~100ms
Source of truth

Edge Evaluation for Low Latency

Evaluate flags at the edge (CDN) for the best of both worlds: server-side security with client-side speed.

// middleware.ts - runs at the edge
import { NextResponse } from 'next/server'
import { evaluateFlag } from '@sylphx/sdk/edge'

export const config = {
  matcher: '/dashboard/:path*',
}

export async function middleware(request: Request) {
  const userId = getUserIdFromCookie(request)

  // Evaluate at the edge - ~10ms globally
  const showNewDashboard = await evaluateFlag('new_dashboard', {
    userId,
    // Flag rules cached at edge
  })

  if (showNewDashboard) {
    // Rewrite to new dashboard
    return NextResponse.rewrite(new URL('/dashboard-v2', request.url))
  }

  return NextResponse.next()
}

Edge Caching Strategy

Flag rules are cached at 200+ edge locations worldwide. When rules change, we use cache-busting to ensure updates propagate within seconds. The SDK handles this automatically.

Offline Mode Support

Keep your app functional even when offline. Cached flag values are used automatically when the network is unavailable.

Offline Configuration
import { SylphxProvider } from '@sylphx/sdk/react'

function App() {
  return (
    <SylphxProvider
      projectId="proj_xxx"

      offline={{
        // Enable offline support
        enabled: true,

        // Pre-load these flags for offline use
        preloadFlags: ['core_feature', 'ui_theme', 'api_version'],

        // Default values when offline and no cache
        defaults: {
          core_feature: true,
          ui_theme: 'light',
          api_version: 'v1',
        },

        // Callback when going offline/online
        onStatusChange: (isOnline) => {
          console.log(`Network status: ${isOnline ? 'online' : 'offline'}`)
        },
      }}
    >
      <MyApp />
    </SylphxProvider>
  )
}

// Check network status in components
import { useNetworkStatus } from '@sylphx/sdk/react'

function StatusIndicator() {
  const { isOnline, lastSync } = useNetworkStatus()

  return (
    <div>
      {isOnline ? (
        <span className="text-green-500">Online</span>
      ) : (
        <span className="text-yellow-500">
          Offline (last sync: {lastSync.toLocaleString()})
        </span>
      )}
    </div>
  )
}
Offline Behavior
Online
Fresh evaluation with latest rules
Offline (cached)
Uses cached rules from last sync
Offline (no cache)
Falls back to configured defaults
Reconnected
Auto-syncs latest rules in background

Sync Intervals and Freshness

Configure how often flags are synced and how stale data is handled. Balance freshness against network usage.

// Regular polling for updates
<SylphxProvider
  sync={{
    // Poll for updates every 60 seconds
    pollingInterval: 60 * 1000,

    // Only poll when tab is visible
    pauseWhenHidden: true,

    // Immediate sync on visibility change
    syncOnFocus: true,
  }}
>

Freshness Trade-offs

Shorter sync intervals mean fresher data but more network requests. For most apps, 60 second polling or streaming is ideal. Use shorter intervals (5-15s) only for critical flags.

Fallback Values

Define fallback values for when flags cant be evaluated. Ensures your app always has sensible defaults.

Fallback Configuration
// Global fallback values
<SylphxProvider
  projectId="proj_xxx"

  fallbacks={{
    // Default values for all flags
    defaults: {
      new_feature: false,        // Boolean flag
      ui_theme: 'system',        // String flag
      max_upload_mb: 10,         // Number flag
      checkout_config: {         // JSON flag
        maxItems: 25,
        enableCoupons: true,
      },
    },

    // Strategy when evaluation fails
    strategy: 'default', // 'default' | 'cached' | 'error'
  }}
>

// Per-flag fallback
const { enabled } = useFeatureFlag('new_feature', {
  fallback: true, // Override default fallback
})

// With loading handling
const { enabled, loading, error } = useFeatureFlag('new_feature')

if (loading) return <Skeleton />
if (error) {
  // Log error, use fallback
  console.error('Flag evaluation failed:', error)
}

// enabled will be the fallback if evaluation failed

Fallback Strategies

defaultBest for: Most applications

Use configured default value. Safest for production.

cachedBest for: High-availability apps

Use last known good value from cache. Good for brief outages.

errorBest for: Access control flags

Throw error on failure. Use when flag is critical.

Performance Comparison

Compare evaluation latencies across different strategies.

StrategyLatencyFreshnessUse Case
Memory Cache<0.1msDepends on syncUI flags, hot paths
LocalStorage<1msPersistedOffline support
Edge (CDN)5-20msSecondsServer components
API (Origin)50-200msReal-timeCritical flags

API Reference

MethodDescription
flagsClient.refresh()Force sync latest flag rules
flagsClient.clearCache()Clear all cached flag data
flagsClient.getCacheStatus()Get cache age and status
useNetworkStatus()Hook for online/offline status
evaluateRules(rules, key, ctx)Evaluate flag with local rules