Open-source feature flag management platform with sub-millisecond evaluation, real-time updates, and zero vendor lock-in.
Website · Documentation · Dashboard · Issues
Existing feature flag platforms force you to choose between unpredictable pricing (LaunchDarkly's per-MAU model), operational burden (self-hosted open-source), or vendor lock-in (proprietary SDKs). FeatureSignals eliminates these trade-offs:
- Transparent pricing -- flat tiers based on seats and environments, never per-evaluation or per-MAU.
- OpenFeature-native -- all SDKs implement OpenFeature providers. Switch away with zero code changes.
- Sub-millisecond evaluation -- SDKs cache the full ruleset locally. Flag checks read from memory, not the network.
- Single Go binary -- the entire API server is one statically-linked binary. No Redis, no message queues, just PostgreSQL.
- Multi-deployment -- run as SaaS, in your private cloud, or fully on-premises with the same codebase.
| Category | What You Get |
|---|---|
| Flag Types | Boolean, string, number, JSON |
| Targeting | User attributes, segments, percentage rollouts (sticky via consistent hashing) |
| Advanced Rules | Prerequisite flags, mutual exclusion groups, flag scheduling, kill switch |
| Real-Time | SSE streaming -- SDKs receive flag changes within seconds |
| Governance | Approval workflows, tamper-evident audit log, per-environment RBAC |
| Webhooks | HMAC-signed delivery with retry to Slack, PagerDuty, or any HTTP endpoint |
| Observability | Evaluation metrics, flag health dashboard, stale flag detection |
| A/B Testing | Variant flag type with consistent assignment and metric callback API |
| Relay Proxy | Lightweight Go binary for edge caching and air-gapped environments |
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ Dashboard │ │ SDKs │ │ REST Client │
│ (Next.js) │ │ Go/Node/Py │ │ (curl, etc) │
│ │ │ Java/C#/Ruby │ │ │
│ │ │ React/Vue │ │ │
└──────┬───────┘ └──────┬────────┘ └──────┬───────┘
│ JWT │ API Key │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ Go API Server (chi router) │
│ Auth · Rate Limiting · CORS · Structured Logging │
├──────────────────────────┬──────────────────────────────┤
│ Management API │ Evaluation API (hot path) │
│ ───────────── │ ────────────────────────── │
│ CRUD: flags, segments, │ POST /v1/evaluate │
│ projects, environments, │ POST /v1/evaluate/bulk │
│ API keys, audit log │ GET /v1/client/{env}/flags │
│ │ GET /v1/stream/{env} (SSE) │
├──────────────────────────┴──────────────────────────────┤
│ In-Memory Ruleset Cache (invalidated via PG NOTIFY) │
├─────────────────────────────────────────────────────────┤
│ PostgreSQL 16 │
└─────────────────────────────────────────────────────────┘
Zero database calls on the evaluation hot path. Flags are evaluated from an in-memory cache, refreshed in real time through PostgreSQL LISTEN/NOTIFY.
The fastest way to run the full stack locally -- API server, dashboard, and PostgreSQL:
git clone https://github.com/dinesh-g1/featuresignals.git
cd featuresignals
docker compose up| Service | URL |
|---|---|
| API | http://localhost:8080 |
| Dashboard | http://localhost:3000 |
| Postgres | localhost:5432 |
Health check:
curl http://localhost:8080/healthcd server
cp .env.example .env
make dev # Starts Postgres, runs migrations, launches serverSee the full Server README for detailed setup, Makefile targets, and API examples.
cd server && make seed
# Creates: Acme Corp org, admin@acme.com / password123, 3 environments, 3 flagsAll server-side SDKs evaluate flags locally from an in-memory cache. Zero network calls per flag check. Server SDKs implement OpenFeature providers for zero vendor lock-in.
| SDK | Type | Package | Runtime |
|---|---|---|---|
| Go | Server | github.com/featuresignals/sdk-go |
Go 1.22+ |
| Node.js | Server | @featuresignals/node |
Node 22+ |
| Python | Server | featuresignals |
Python 3.9+ |
| Java | Server | com.featuresignals:sdk-java |
Java 17+ |
| .NET/C# | Server | FeatureSignals |
.NET 8.0+ |
| Ruby | Server | featuresignals |
Ruby 3.1+ |
| React | Client | @featuresignals/react |
React 18+ |
| Vue | Client | @featuresignals/vue |
Vue 3.3+ |
go get github.com/featuresignals/sdk-goclient := fs.NewClient("fs_srv_xxx", "production",
fs.WithBaseURL("http://localhost:8080"),
fs.WithSSE(true),
)
defer client.Close()
<-client.Ready()
user := fs.NewContext("user-42").WithAttribute("plan", "pro")
enabled := client.BoolVariation("new-checkout", user, false)npm install @featuresignals/nodeimport { init } from "@featuresignals/node";
const client = init("fs_srv_xxx", {
envKey: "production",
baseURL: "http://localhost:8080",
streaming: true,
});
await client.waitForReady();
const enabled = client.boolVariation("new-checkout", { key: "user-42" }, false);npm install @featuresignals/reactimport { FeatureSignalsProvider, useFlag } from "@featuresignals/react";
function App() {
return (
<FeatureSignalsProvider sdkKey="fs_cli_xxx" envKey="production">
<MyComponent />
</FeatureSignalsProvider>
);
}
function MyComponent() {
const showCheckout = useFlag("new-checkout", false);
return showCheckout ? <NewCheckout /> : <OldCheckout />;
}pip install featuresignalsfrom featuresignals import FeatureSignalsClient, ClientOptions, EvalContext
client = FeatureSignalsClient("fs_srv_xxx", ClientOptions(env_key="production"))
client.wait_for_ready()
user = EvalContext(key="user-42", attributes={"plan": "pro"})
enabled = client.bool_variation("new-checkout", user, False)<dependency>
<groupId>com.featuresignals</groupId>
<artifactId>sdk-java</artifactId>
<version>0.1.0</version>
</dependency>var options = new ClientOptions("production")
.baseURL("http://localhost:8080");
var client = new FeatureSignalsClient("fs_srv_xxx", options);
client.waitForReady(5000);
var user = new EvalContext("user-42").withAttribute("plan", "pro");
boolean enabled = client.boolVariation("new-checkout", user, false);dotnet add package FeatureSignalsusing FeatureSignals;
var options = new ClientOptions { EnvKey = "production" };
using var client = new FeatureSignalsClient("fs_srv_xxx", options);
await client.WaitForReadyAsync();
var user = new EvalContext("user-42").WithAttribute("plan", "pro");
bool enabled = client.BoolVariation("new-checkout", user, false);gem install featuresignalsrequire "featuresignals"
options = FeatureSignals::ClientOptions.new(env_key: "production")
client = FeatureSignals::Client.new("fs_srv_xxx", options)
client.wait_for_ready
user = FeatureSignals::EvalContext.new(key: "user-42", attributes: { "plan" => "pro" })
enabled = client.bool_variation("new-checkout", user, false)npm install @featuresignals/vue// main.ts
import { createApp } from "vue";
import { FeatureSignalsPlugin } from "@featuresignals/vue";
import App from "./App.vue";
createApp(App)
.use(FeatureSignalsPlugin, { sdkKey: "fs_cli_xxx", envKey: "production" })
.mount("#app");<script setup>
import { useFlag } from "@featuresignals/vue";
const showCheckout = useFlag("new-checkout", false);
</script>
<template>
<NewCheckout v-if="showCheckout" />
<OldCheckout v-else />
</template>featuresignals/
├── server/ # Go API server, relay proxy, stale flag scanner
│ ├── cmd/
│ │ ├── server/ # Main API server binary
│ │ ├── relay/ # Relay proxy binary
│ │ └── stalescan/ # Stale flag code scanner
│ ├── internal/ # Core packages (api, auth, eval, store, sse, ...)
│ ├── migrations/ # PostgreSQL migrations (golang-migrate)
│ └── Makefile
├── dashboard/ # Next.js admin UI
├── website/ # Astro marketing site (featuresignals.com)
├── docs/ # Docusaurus documentation (docs.featuresignals.com)
├── sdks/
│ ├── go/ # Go SDK
│ ├── node/ # Node.js/TypeScript SDK
│ ├── python/ # Python SDK
│ ├── java/ # Java SDK
│ ├── dotnet/ # .NET/C# SDK
│ ├── ruby/ # Ruby SDK
│ ├── react/ # React SDK (hooks)
│ └── vue/ # Vue SDK (composables)
├── deploy/ # Dockerfiles, Caddyfile, Helm chart, Terraform, scripts
│ ├── docker/ # Dockerfile.server, .dashboard, .website, .docs, .relay
│ ├── helm/ # Kubernetes Helm chart
│ └── terraform/ # AWS Terraform modules
├── docker-compose.yml # Local development stack
├── docker-compose.prod.yml # Production stack with Caddy
└── .github/workflows/ # CI/CD pipelines
A lightweight Go binary that caches flag rulesets locally, reducing latency and API load. Ideal for on-premises or air-gapped deployments.
# Build
cd server && go build -o bin/relay ./cmd/relay
# Run
./bin/relay \
-api-key fs_srv_xxx \
-env-key production \
-upstream https://api.featuresignals.com \
-port 8090Point your SDKs at the relay instead of the central API. The relay serves GET /v1/client/{envKey}/flags and stays in sync via SSE or polling.
Scans your codebase for flag key references and reports which flags have no code references (stale). Supports Go, TypeScript, Python, Java, and 10+ other languages.
# Build
cd server && go build -o bin/stalescan ./cmd/stalescan
# Run
./bin/stalescan \
-token <jwt> \
-project <project-id> \
-dir /path/to/your/codebase \
-ci # Exit 1 if stale flags found (for CI pipelines)docker compose upThe production stack runs behind Caddy with automatic HTTPS:
docker compose -f docker-compose.prod.yml up -dSee the Deployment Guide for full production setup, including DNS configuration, environment variables, CI/CD pipeline, and backup strategy.
FeatureSignals runs as a single Docker Compose stack or Kubernetes Helm chart:
- Docker Compose --
docker compose upwith your own PostgreSQL - Helm Chart --
helm install featuresignals deploy/helm/featuresignals/ - Single Binary -- download the Go binary and point it at a PostgreSQL connection string
Requirements: PostgreSQL 16+, 1 CPU / 512MB RAM minimum.
| Component | Technology |
|---|---|
| API Server | Go 1.25, chi router, pgx |
| Database | PostgreSQL 16 |
| Cache Invalidation | PostgreSQL LISTEN/NOTIFY |
| Streaming | Server-Sent Events (SSE) |
| Dashboard | Next.js 16, React 19, Tailwind 4, Radix UI |
| Marketing Site | Astro |
| Documentation | Docusaurus |
| Reverse Proxy | Caddy (auto-HTTPS) |
| CI/CD | GitHub Actions |
| Containerization | Docker Compose |
# Register
curl -X POST http://localhost:8080/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"securepass123","name":"Dev","org_name":"My Org"}'
# Login
curl -X POST http://localhost:8080/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"securepass123"}'# Single flag
curl -X POST http://localhost:8080/v1/evaluate \
-H "X-API-Key: fs_srv_xxx" \
-H "Content-Type: application/json" \
-d '{"flag_key":"new-checkout","context":{"key":"user-42","attributes":{"plan":"pro"}}}'
# All flags for a context
curl http://localhost:8080/v1/client/production/flags?key=user-42 \
-H "X-API-Key: fs_srv_xxx"
# Real-time streaming
curl -N "http://localhost:8080/v1/stream/production?api_key=fs_srv_xxx"See the Server README for complete API examples including flag CRUD, targeting rules, segments, and bulk evaluation.
We welcome contributions. Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Run the full stack locally:
docker compose up - Run server tests:
cd server && make test - Submit a pull request
Please ensure all tests pass and new code follows the existing patterns (interface-driven design, structured logging, etc.).
FeatureSignals is open source under the Apache License 2.0.
Copyright 2026 G Dinesh Reddy / FeatureSignals