pbflags

module
v0.16.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2026 License: MIT

README

pbflags

Protocol Buffer-based feature flags with type-safe code generation, multi-tier caching, and a never-throw guarantee.

Note: This project is a learning exercise and research exploration into protobuf-driven feature flag design. It was extracted from a production system to study the patterns independently. If you're building a real product and need feature flags, you probably want Flipt, OpenFeature, or Unleash instead. Those are battle-tested, well-supported, and have ecosystems around them. pbflags exists because we found the proto-as-source-of-truth pattern interesting and wanted to share it.

Overview

pbflags lets you define feature flag schemas as protobuf messages, define flag behavior in YAML config files, and generate type-safe client code for Go and Java. Proto is the source of truth for flag identity, types, defaults, and evaluation context dimensions; YAML config is the source of truth for condition chains; the database stores synced runtime state for evaluators.

For AI agents

If you are an AI agent integrating pbflags into a consumer project, start with docs/agent-setup.md. It is the shortest end-to-end setup path and avoids maintainer-only details from the rest of the docs.

Prerequisites

  • Go 1.26+
  • PostgreSQL (or Docker for docker compose up)
  • Buf CLI

Quick Start

1. Define flags in proto
syntax = "proto3";
import "pbflags/options.proto";

enum PlanLevel {
  PLAN_LEVEL_UNSPECIFIED = 0;
  PLAN_LEVEL_FREE = 1;
  PLAN_LEVEL_PRO = 2;
  PLAN_LEVEL_ENTERPRISE = 3;
}

// Exactly one message must carry (pbflags.context).
// Each field annotated with (pbflags.dimension) becomes a typed dimension
// constructor in the generated `dims` package.
message EvaluationContext {
  option (pbflags.context) = {};

  string user_id = 1 [(pbflags.dimension) = {
    description: "Authenticated user identifier"
    hashable: true
  }];

  PlanLevel plan = 2 [(pbflags.dimension) = {description: "Subscription tier"}];
}

message Notifications {
  option (pbflags.feature) = {
    id: "notifications"
    description: "Notification delivery controls"
    owner: "platform-team"
  };

  bool email_enabled = 1 [(pbflags.flag) = {
    description: "Enable email notifications"
    default: { bool_value: { value: true } }
  }];

  string digest_frequency = 2 [(pbflags.flag) = {
    description: "Digest email frequency"
    default: { string_value: { value: "daily" } }
  }];
}
2. Generate client code

Add pbflags to your buf.yaml and generate:

# buf.yaml
# deps:
#   - buf.build/spotlightgov/pbflags

go install github.com/SpotlightGOV/pbflags/cmd/protoc-gen-pbflags@latest
buf dep update
buf generate --template buf.gen.flags.yaml
buf build proto -o descriptors.pb

Example buf.gen.flags.yaml for Go:

version: v2
plugins:
  - local: protoc-gen-pbflags
    out: gen/flags
    strategy: all
    opt:
      - lang=go
      - package_prefix=github.com/yourorg/yourrepo/gen/flags
inputs:
  - directory: proto
3. Define flag behavior

Create one YAML config file per feature:

# features/notifications.yaml
feature: notifications
flags:
  email_enabled:
    conditions:
      - when: "ctx.plan == PlanLevel.ENTERPRISE"
        value: true
      - otherwise: false
  digest_frequency:
    value: "daily"

Validate it before syncing:

pbflags-sync validate --descriptors=descriptors.pb --features=./features
4. Run the server
pbflags-admin --standalone \
  --descriptors=descriptors.pb \
  --features=./features \
  --database=postgres://user:pass@localhost:5432/mydb?sslmode=disable

This starts the admin UI on :9200 and the evaluator on :9201. Migrations, definition sync, and evaluation all happen in one process.

Or use Docker Compose:

docker compose -f docker/docker-compose.yml up
5. Use in your application
import (
  "net/http"

  pb "github.com/yourorg/yourrepo/gen/proto"
  "github.com/yourorg/yourrepo/gen/flags/dims"
  "github.com/yourorg/yourrepo/gen/flags/notificationsflags"
  "github.com/SpotlightGOV/pbflags/pbflags"
)

// Create an evaluator connected to the pbflags service.
// The zero-value EvaluationContext is used as a prototype.
eval := pbflags.Connect(http.DefaultClient, "http://localhost:9201", &pb.EvaluationContext{})

// Bind dimensions — With() is immutable, returning a new evaluator.
eval = eval.With(dims.UserID("user-123"), dims.Plan(pb.PlanLevel_PLAN_LEVEL_PRO))

// Create the typed feature client.
notifications := notificationsflags.New(eval)

emailEnabled := notifications.EmailEnabled(ctx)    // bool
frequency := notifications.DigestFrequency(ctx)     // string

You can also propagate the evaluator through context.Context:

// Middleware: store the evaluator in context.
ctx = pbflags.ContextWith(ctx, eval)

// Handler: retrieve it and create feature clients.
eval := pbflags.FromContext(ctx)
notifications := notificationsflags.New(eval)

Language Support

Language Status Package
Go Stable go get github.com/SpotlightGOV/pbflags
Java Stable org.spotlightgov.pbflags:pbflags-java (Maven Central)
Java Testing Stable org.spotlightgov.pbflags:pbflags-java-testing
TypeScript Planned -
Rust Planned -
Node Planned -

Documentation

As-built documentation lives in docs/. Design research and explorations live in research/.

Document Description
Agent Setup Step-by-step integration guide for AI agents
Deployment Service topology, standalone and production setup, admin UI, configuration
Upgrading Upgrade procedures for standalone and multi-instance deployments
Go Client Go codegen setup, buf configuration, generated API surface
Java Client Java codegen setup, Dagger integration, testing utilities
Philosophy Design principles, evaluation context, dimensions, lint tool
Contributing Dev setup, testing, releasing, migration rules
Troubleshooting Common errors and how to resolve them
Roadmap Planned features and sequencing

License

MIT

Directories

Path Synopsis
cmd
pbflags-admin command
Binary pbflags-admin is the flag management control plane.
Binary pbflags-admin is the flag management control plane.
pbflags-evaluator command
Binary pbflags-evaluator is the read-only flag resolution service.
Binary pbflags-evaluator is the read-only flag resolution service.
pbflags-lint command
pbflags-lint detects breaking changes in pbflags proto definitions by comparing the working tree against a base git ref.
pbflags-lint detects breaking changes in pbflags proto definitions by comparing the working tree against a base git ref.
pbflags-sync command
pbflags-sync reads a descriptors.pb file and syncs feature/flag definitions into PostgreSQL.
pbflags-sync reads a descriptors.pb file and syncs feature/flag definitions into PostgreSQL.
protoc-gen-pbflags command
protoc-gen-pbflags generates type-safe flag client code from feature proto definitions.
protoc-gen-pbflags generates type-safe flag client code from feature proto definitions.
Package db provides embedded database migrations for pbflags.
Package db provides embedded database migrations for pbflags.
gen
internal
admin/web
Package web provides an embedded admin dashboard for the pbflags feature flag system.
Package web provides an embedded admin dashboard for the pbflags feature flag system.
celenv
Package celenv builds CEL type environments from EvaluationContext proto message descriptors.
Package celenv builds CEL type environments from EvaluationContext proto message descriptors.
codegen/contextutil
Package contextutil discovers the EvaluationContext proto message and extracts dimension metadata for codegen backends.
Package contextutil discovers the EvaluationContext proto message and extracts dimension metadata for codegen backends.
codegen/gogen
Package gogen generates Go flag client code from feature proto definitions.
Package gogen generates Go flag client code from feature proto definitions.
codegen/javagen
Package javagen generates Java flag client code from feature proto definitions.
Package javagen generates Java flag client code from feature proto definitions.
configcli
Package configcli implements the "config validate" and "config show" CLI commands for offline YAML config validation and inspection.
Package configcli implements the "config validate" and "config show" CLI commands for offline YAML config validation and inspection.
configexport
Package configexport generates YAML flag configuration files from existing database state.
Package configexport generates YAML flag configuration files from existing database state.
configfile
Package configfile parses and validates YAML flag configuration files.
Package configfile parses and validates YAML flag configuration files.
flagfile
Package flagfile reads picocli-style @file references and expands them into a flat argument slice.
Package flagfile reads picocli-style @file references and expands them into a flat argument slice.
flagfmt
Package flagfmt provides shared types and formatting for flag values and condition-chain JSON.
Package flagfmt provides shared types and formatting for flag values and condition-chain JSON.
lint
Package lint detects breaking changes between two versions of pbflags proto definitions.
Package lint detects breaking changes between two versions of pbflags proto definitions.
projectconfig
Package projectconfig loads .pbflags.yaml project configuration.
Package projectconfig loads .pbflags.yaml project configuration.
sync
Package sync provides flag definition synchronization from parsed descriptors into PostgreSQL.
Package sync provides flag definition synchronization from parsed descriptors into PostgreSQL.
testdb
Package testdb provides a shared PostgreSQL test container for integration tests.
Package testdb provides a shared PostgreSQL test container for integration tests.
Package pbflags provides core types for the pbflags evaluation context.
Package pbflags provides core types for the pbflags evaluation context.
Package pbflagstest provides test helpers for pbflags consumers.
Package pbflagstest provides test helpers for pbflags consumers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL