Skip to content

docs: ADR for modular flagd builder (OTel Collector-style)#1920

Draft
aepfli wants to merge 6 commits intoopen-feature:mainfrom
open-feature-forking:adr/modular-builder
Draft

docs: ADR for modular flagd builder (OTel Collector-style)#1920
aepfli wants to merge 6 commits intoopen-feature:mainfrom
open-feature-forking:adr/modular-builder

Conversation

@aepfli
Copy link
Copy Markdown
Member

@aepfli aepfli commented Apr 1, 2026

Summary

This ADR proposes adopting an OpenTelemetry Collector Builder-style modular build system for flagd.

Problem

flagd compiles all sync providers (file, HTTP, gRPC, Kubernetes, GCS, Azure Blob, S3), all service endpoints (flag-evaluation, OFREP, flag-sync), and their heavy dependencies (~700 transitive deps in core/go.mod) into every binary — regardless of what the user needs.

Proposed Solution

A flagd-builder CLI tool that reads a YAML manifest and generates a custom flagd binary with only the selected components:

  • Sync providers: file, http, grpc, kubernetes, gcs, azblob, s3 (selectable)
  • Service endpoints: flag-evaluation, ofrep, flag-sync (selectable)
  • Evaluators: jsonlogic, wasm (selectable)
  • Middleware: cors, h2c, metrics (selectable)
  • User extensions: custom components via own Go modules, no forking required

Key Design Points

  • Factory interfaces (SyncFactory, ServiceFactory, EvaluatorFactory, MiddlewareFactory) for all component types
  • Each component becomes a separate Go module with its own go.mod
  • Standard distributions: minimal, cloud, kubernetes, full
  • Backward compatible: flagd-full replicates current behavior

Open Questions (looking for feedback)

  1. Module path structure (top-level vs. under existing paths)
  2. Should flagd-proxy also use the builder?
  3. Independent vs. lockstep versioning for component modules
  4. Community component registry (like OTel contrib)?
  5. Can a build have zero service endpoints (library/embedded mode)?
  6. CLI flag compatibility with the existing -f/--sources flags

cc @open-feature/flagd-maintainers

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 1, 2026

Deploy Preview for polite-licorice-3db33c ready!

Name Link
🔨 Latest commit 7fd0212
🔍 Latest deploy log https://app.netlify.com/projects/polite-licorice-3db33c/deploys/69cced87a095cf00084907ad
😎 Deploy Preview https://deploy-preview-1920--polite-licorice-3db33c.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an Architecture Decision Record for a modular flagd builder, allowing users to create custom binaries with specific components to reduce dependency bloat. The review feedback suggests improving the consistency of the factory interfaces by using dependency structs for sync providers and evaluators, and notes the omission of the MiddlewareFactory interface. There is also a concern regarding the increased complexity in the Runtime struct when transitioning to a dynamic service registry.

Propose adopting an OTel Collector Builder-style approach for flagd,
enabling users to compose custom binaries with only the sync providers,
service endpoints, evaluators, and middleware they need.

Key points:
- Factory interfaces for all component types (sync, service, evaluator, middleware)
- Each component becomes a separate Go module with its own go.mod
- YAML manifest-driven code generation and compilation
- Standard distributions (minimal, cloud, kubernetes, full)
- User extensibility: custom components via own Go modules, no forking required

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
@aepfli aepfli force-pushed the adr/modular-builder branch from 0a845e8 to c46c10f Compare April 1, 2026 08:33
aepfli and others added 5 commits April 1, 2026 10:48
- Add telemetry.Provider interface and TelemetryFactory as 5th component type
- Document current OTel coupling issues (global tracer, hardcoded otelgrpc/otelhttp)
- Add telemetry/otel and telemetry/noop modules to module structure
- Add telemetry column to standard distributions table
- Add telemetry granularity open question
- Inject telemetry into ServiceDependencies and EvaluatorFactory

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
- Use dependency structs for all factory Create methods (SyncDependencies,
  EvaluatorDependencies, MiddlewareDependencies) for consistency and
  forward compatibility
- Add missing MiddlewareFactory interface definition
- Address Runtime complexity concern: introduce EventBus for cross-service
  coordination instead of relying on typed method calls (e.g. Emit()),
  avoiding type assertions while keeping the dynamic service registry

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Analyze four options for how -f/--sources CLI flags interact with
modular builds. Recommend Option A+D: keep -f as-is with fail-fast
errors on unknown schemes, plus a 'flagd components' introspection
command. Mirrors the OTel Collector's approach.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Keep it simple: a single telemetry.Provider interface covers both
tracing and metrics. Independent selection can be revisited later.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Describe how the modular architecture enables a snapshot-based
resilience pattern for high availability:
- Snapshot writer subscribes to EventBus, persists flag state to disk
- Snapshot sync provider loads cached state on startup as lowest-
  precedence source
- flagd serves from cache immediately, live data overwrites when
  upstream connects
- Composes with any sync provider, zero changes to store/evaluator

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 1, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant