Skip to main content

Latency benchmarks, payload sizes, protocol comparisons, and optimization strategies

Performance

Flaggr is designed for sub-millisecond flag evaluations at the edge and single-digit millisecond evaluations over the network.

Latency Benchmarks

Evaluation ModeP50P95P99
In-process (local eval)0.01ms0.05ms0.1ms
L1 cache hit0.05ms0.1ms0.2ms
L2 cache hit (Redis)1ms3ms5ms
gRPC evaluation8ms25ms45ms
REST evaluation15ms55ms150ms
OFREP evaluation20ms65ms180ms
Fastest Path

For latency-sensitive paths, use the gRPC provider with localEvaluation: true. After initial sync, evaluations happen in-process in under 0.1ms.

Payload Size Comparison

ProtocolTypical RequestTypical ResponseTotal
REST (JSON)~320 bytes~410 bytes~730 bytes
OFREP (JSON)~280 bytes~350 bytes~630 bytes
Connect (JSON)~300 bytes~380 bytes~680 bytes
gRPC (Protobuf)~95 bytes~120 bytes~215 bytes

gRPC with protobuf is approximately 70% smaller than JSON-based protocols.

Optimization Strategies

1. Use Local Evaluation

The fastest evaluation is one that doesn't hit the network. Local evaluation providers download the flag configuration once and evaluate in-process.

// gRPC with local evaluation
const provider = new GrpcProvider({
  grpcAddress: 'flaggr.dev:50051',
  serviceId: 'my-service',
  localEvaluation: true,
})
 
// In-process provider (no gRPC needed)
const provider = new InProcessProvider({
  apiUrl: 'https://flaggr.dev',
  serviceId: 'my-service',
  pollIntervalMs: 30000,
})

2. Use Bulk Evaluation

Instead of N individual requests, fetch all flags in a single call:

POST /api/connect/bulk-evaluate
{
  "serviceId": "web-app",
  "flagKeys": ["flag-a", "flag-b", "flag-c"],
  "context": { "targetingKey": "user-123" }
}

This reduces N round-trips to 1.

3. Enable Streaming

Instead of polling, use SSE or gRPC streaming to receive flag changes instantly:

const provider = new FlaggrWebProvider({
  enableStreaming: true,
  serviceId: 'web-app',
})

4. Bootstrap Server-Rendered Pages

For SSR/SSG, evaluate flags on the server and pass to the client as bootstrap data:

// Server-side
const flags = await evaluateForUser(userId)
 
// Client-side (zero network calls on load)
const provider = new FlaggrWebProvider({
  bootstrap: flags,
})

5. Cache Configuration

Tune cache TTLs based on your consistency requirements:

const client = createFlaggr({
  serviceId: 'web-app',
  cacheTtl: 30000, // 30s cache for less-critical flags
})
Note

Longer cache TTLs reduce API calls but delay flag change propagation. For real-time updates, use streaming instead of aggressive caching.

Connection Overhead

Connection TypeHandshakePersistentMultiplexed
REST (HTTP/1.1)Per requestKeep-aliveNo
Connect (HTTP/2)OnceYesYes
gRPC (HTTP/2)OnceYesYes
SSE (HTTP/1.1)OnceYesNo

gRPC and Connect reuse a single HTTP/2 connection for all requests, eliminating per-request handshake overhead.

Monitoring Performance

Track evaluation performance via Prometheus:

# P95 evaluation latency
histogram_quantile(0.95, sum(rate(flaggr_http_request_duration_seconds_bucket[5m])) by (le))
 
# Evaluation throughput
sum(rate(flaggr_evaluations_total[5m]))
 
# Cache hit rate
sum(rate(flaggr_cache_operations_total{result="hit"}[5m]))
/ sum(rate(flaggr_cache_operations_total[5m]))