Skip to main content

Choose the right evaluation provider for your architecture — server, browser, edge, gRPC, and hybrid options

Last updated October 3, 2026

Provider Architecture

Flaggr uses a provider pattern to abstract how flags are evaluated. Each provider implements the same interface but optimizes for different deployment environments and access patterns.

Provider Overview

ProviderEnvironmentReal-timeLocal EvalBest For
FlaggrProviderServer (Node.js)NoNoAPI servers, SSR
FlaggrWebProviderBrowserYes (SSE/polling)Cache-firstSPAs, React apps
GrpcProviderServerYes (streaming)YesMicroservices, high-throughput
InProcessProviderAnyPollingYesEdge workers, serverless
FileProviderServerNoYesLocal dev, testing
HybridProviderServerYesYesMixed workloads
StandaloneEvaluatorEdge/WorkersNoYesCloudflare Workers, Deno
EdgeHybridProviderEdgeYesYesEdge with fallback
FetchOnceProviderAnyNoYesShort-lived processes

Server Provider

The default server-side provider. Makes HTTP requests to the Flaggr evaluation API.

import { FlaggrProvider } from '@flaggr/client'
 
const provider = new FlaggrProvider({
  apiUrl: 'https://flaggr.dev',
  apiToken: 'fgr_your_token',
  serviceId: 'api-server',
})
 
const result = await provider.resolveBooleanEvaluation(
  'checkout-v2',
  false,
  { targetingKey: 'user-123', plan: 'enterprise' }
)
// { value: true, reason: 'TARGETING_MATCH', variant: 'enabled' }

When to use: API servers, server-rendered pages, backend services where each evaluation is independent.

Web Provider

Client-side provider optimized for browser environments with real-time updates.

import { FlaggrWebProvider } from '@flaggr/client'
 
const provider = new FlaggrWebProvider({
  apiUrl: 'https://flaggr.dev',
  apiToken: 'fgr_your_token',
  serviceId: 'web-app',
  enableOfflineCache: true,
  enableAnalytics: true,
})

Cache-First Evaluation

The web provider uses a cache-first strategy:

  1. Check in-memory cache for the flag
  2. Return cached value immediately (sub-millisecond)
  3. Fire an async fetch to refresh the cache for next evaluation
  4. Emit change events if the value differs

This means evaluations are always fast, even on slow connections.

Bootstrap Data

For server-rendered pages, pass flags evaluated on the server to avoid a network round-trip on load:

// Server-side
const flags = await evaluateForUser(userId)
 
// Pass to client
const provider = new FlaggrWebProvider({
  bootstrap: {
    'checkout-v2': { value: true, reason: 'TARGETING_MATCH', variant: 'enabled' },
    'dark-mode': { value: false, reason: 'DEFAULT' },
  },
})

Real-Time Updates

Update modes — choose how flag changes reach the client with updateMode, and switch it at runtime with setUpdateMode():

const provider = new FlaggrWebProvider({
  serviceId: 'web-app',
  updateMode: 'auto', // 'auto' | 'stream' | 'batch' | 'poll'
})
 
// Later — tears down the old transport before starting the new one
provider.setUpdateMode('batch')
ModeDeliveryRequests
auto (default)SSE push + 5s batched safety refreshPush + 1 batch/5s
streamSSE push onlyZero polling
batchGrouped refresh every 2s1 batch/2s
pollPer-flag refresh every 2s1 request per tracked flag/2s

Polling ticks are skipped while the tab is hidden; a catch-up refresh runs when the tab becomes visible again. If SSE exhausts its reconnect attempts, the provider degrades to 3s polling automatically.

Transport events — subscribe to requests, SSE messages, queued refreshes, applies, and mode switches (useful for tracing and latency instrumentation):

provider.onTransportEvent((event) => {
  // event.kind: 'request' | 'sse' | 'queue' | 'refresh' | 'apply' | 'mode'
  console.log(event.kind, event.label, event.durationMs)
})

Connection State

Monitor the provider's connection health:

provider.onConnectionStateChange((state) => {
  // state: 'connecting' | 'connected' | 'disconnected' | 'error'
  console.log('Connection:', state)
})

Offline Cache

When enableOfflineCache: true, flags are persisted to localStorage. If the API is unreachable on next load, the provider uses the last-known values.

gRPC Provider

High-performance provider for server-side streaming with local evaluation.

import { GrpcProvider } from '@flaggr/client'
 
const provider = new GrpcProvider({
  grpcAddress: 'flaggr.dev:50051',
  serviceId: 'payment-service',
  environment: 'production',
  apiToken: 'fgr_your_token',
  localEvaluation: true,
  enableFallback: true,
})

Local Evaluation

When localEvaluation: true, the provider downloads the full flag configuration and evaluates locally. This eliminates network latency for each evaluation — flags are evaluated in-process in microseconds.

Flag updates arrive via gRPC server-side streaming in real-time.

Automatic Fallback

When enableFallback: true and the gRPC connection fails, the provider falls back to REST/OFREP evaluation transparently.

Connection Options

const provider = new GrpcProvider({
  grpcAddress: 'flaggr.dev:50051',
  serviceId: 'my-service',
  flagKeys: ['checkout-v2', 'dark-mode'], // Subscribe to specific flags (empty = all)
  connectionTimeoutMs: 10000,             // Connection timeout (default: 10s)
  tls: {
    certPath: '/path/to/cert.pem',
    keyPath: '/path/to/key.pem',
    caPath: '/path/to/ca.pem',
  },
  reconnect: {
    enabled: true,
    maxAttempts: 10,
    initialDelayMs: 1000,
    maxDelayMs: 30000,
  },
})

In-Process Provider

Downloads flags from a URL or API and evaluates entirely in-process. Good for serverless and edge.

import { InProcessProvider } from '@flaggr/client'
 
const provider = new InProcessProvider({
  apiUrl: 'https://flaggr.dev',
  serviceId: 'edge-worker',
  apiToken: 'fgr_your_token',
  pollIntervalMs: 30000, // Refresh every 30s
})
 
await provider.initialize()

All evaluations are local — no network calls after initialization.

File Provider

Loads flags from a local JSON file. Ideal for development and testing.

import { FileProvider } from '@flaggr/client'
 
const provider = new FileProvider({
  filePath: './flags.json',
})

flags.json:

{
  "flags": [
    {
      "key": "checkout-v2",
      "type": "boolean",
      "enabled": true,
      "defaultValue": false,
      "variants": [],
      "targeting": []
    }
  ]
}

Hybrid Provider

Combines local evaluation with remote updates. Evaluates locally when possible, falls back to remote.

import { HybridProvider } from '@flaggr/client'
 
const provider = new HybridProvider({
  apiUrl: 'https://flaggr.dev',
  serviceId: 'my-service',
  apiToken: 'fgr_your_token',
  localFirst: true,
})

Standalone Evaluator

Zero-dependency evaluator for edge runtimes (Cloudflare Workers, Deno Deploy). No Node.js APIs required.

import { StandaloneEvaluator } from '@flaggr/client'
 
const evaluator = new StandaloneEvaluator()
 
const flags = await fetch('https://flaggr.dev/api/flags?serviceId=edge-app')
  .then(r => r.json())
 
const result = evaluator.evaluate(flags['checkout-v2'], {
  targetingKey: 'user-123',
  plan: 'enterprise',
})

Choosing a Provider

Start here:

  • React SPA? → FlaggrWebProvider with updateMode: 'auto' (default)
  • Next.js SSR? → FlaggrProvider server-side + FlaggrWebProvider client-side with bootstrap
  • Node.js API? → GrpcProvider (high-throughput) or FlaggrProvider (simple)
  • Edge/Workers? → StandaloneEvaluator or InProcessProvider
  • Local dev? → FileProvider
  • Testing? → FileProvider with test fixture JSON

Decision factors:

FactorRecommendation
Latency-sensitivegRPC or In-Process (local evaluation)
Real-time updates neededgRPC (streaming) or Web (SSE)
Minimal dependenciesStandaloneEvaluator
Serverless/statelessFetchOnceProvider or InProcessProvider
Offline supportWebProvider with enableOfflineCache
Server-rendered + clientServer provider + Web provider with bootstrap