FeatureSignals

Architecture Overview

FeatureSignals is built on a hexagonal architecture with a Go API server at the core, PostgreSQL for persistence, Redis for evaluation caching, and a stateless evaluation engine that serves sub-millisecond flag resolutions. This page gives you the high-level picture.

System Topology

A FeatureSignals deployment typically looks like this:

┌──────────────────────────────────────────────────────────────┐
│                     LOAD BALANCER                             │
│                  (NGINX / Cloud LB)                           │
└──────────┬─────────────────────────────────────┬─────────────┘
           │                                     │
    ┌──────▼──────┐  ┌──────────┐       ┌──────▼──────┐
    │ API Server 1 │  │   ...    │       │ API Server N│
    │  (Go, chi)   │  │          │       │  (Go, chi)  │
    └──────┬───────┘  └──────────┘       └──────┬───────┘
           │                                     │
    ┌──────▼──────┐                       ┌──────▼──────┐
    │    Redis    │◄──── PG LISTEN ──────►│    Redis    │
    │  (Cache)    │       /NOTIFY         │  (Cache)    │
    └─────────────┘                       └─────────────┘
           │                                     │
           └──────────────┬──────────────────────┘
                          │
                   ┌──────▼──────┐
                   │ PostgreSQL  │
                   │  (Primary)  │
                   └─────────────┘
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
   ┌────▼────┐     ┌─────▼─────┐     ┌────▼────┐
   │  SDK    │     │  Relay    │     │ Webhooks│
   │ Clients │     │  Proxy    │     │  (Async)│
   └─────────┘     └───────────┘     └─────────┘

All server instances are stateless and interchangeable. The Redis cache is populated at startup and invalidated in real-time via PostgreSQL LISTEN/NOTIFY. SDKs connect to the API or Relay Proxy for flag evaluation.

Core Components

Go API Server

The core application server. Handles REST APIs, authentication, authorization, and webhook delivery. Built with hexagonal architecture — domain logic is fully isolated from infrastructure adapters.

PostgreSQL

Primary data store for organizations, projects, flags, segments, audit logs, and user accounts. Every query uses parameterized statements; every foreign key is indexed.

Redis Cache

In-memory cache for compiled flag rulesets. Evaluation requests never touch the database — they read from Redis. Cache invalidation uses PG LISTEN/NOTIFY for real-time propagation across all server instances.

Evaluation Engine

The hot path. A stateless, allocation-minimizing Go engine that evaluates flags in <1ms p99. Runs the evaluation order: existence check → environment state → mutual exclusion → prerequisites → targeting → rollout → variant assignment.

Relay Proxy

Optional sidecar that caches flag rules locally. Eliminates network hops for evaluation in high-throughput or air-gapped environments. Syncs via WebSocket or polling.

SDKs

OpenFeature-native client libraries for Go, Node.js, Python, Java, Ruby, .NET, JavaScript, React, iOS, and Android. Each SDK handles caching, retries, and graceful degradation independently.

Hexagonal Architecture

The Go server follows a ports-and-adapters (hexagonal) architecture. Domain logic sits at the center with zero dependencies on infrastructure:

handlers (HTTP) ──→ domain interfaces (ports) ←── store/postgres (DB adapter)
                 ──→ domain entities & logic  ←── cache adapter
                 ──→ eval engine              ←── webhook adapter
  • Handlers only import domain interfaces — never concrete implementations.
  • Domain logic is pure Go with no database, HTTP, or cache dependencies.
  • Adapters (PostgreSQL store, Redis cache, webhook sender) implement domain interfaces and are wired in at startup.
  • This means you can swap PostgreSQL for another database, or add gRPC alongside REST, without touching business logic.

Evaluation Hot Path

The flag evaluation path is the most performance-critical code in the system. It's designed for sub-millisecond latencies:

  1. SDK checks local cache. If the flag ruleset is cached and fresh, evaluate locally. No network call.
  2. SDK calls evaluation API. If the local cache is stale or missing, the SDK calls POST /v1/evaluate or the client-side evaluation endpoint.
  3. API server reads from Redis. The compiled ruleset is fetched from Redis. No database query.
  4. Evaluation engine resolves the flag. A stateless, allocation-minimizing Go engine runs the evaluation order and returns the result.
  5. SDK caches the result. The SDK updates its local cache and returns the value to the application.

Deployment Models

ModelDescriptionBest For
FeatureSignals CloudFully managed SaaS. Multi-tenant, SOC 2 compliant, 99.95% SLA.Most teams. Fastest time to value.
Dedicated CloudSingle-tenant instance in your cloud (AWS, GCP, Azure). Isolated infrastructure.Enterprises with compliance or data residency requirements.
Self-HostedDeploy in your own infrastructure. Full control over data, networking, and upgrades.Regulated industries, air-gapped environments, or teams that require full control.

Deep Dives