Deep Study: Architecture, GitOps Pattern, A/B Testing & SDK Integration
GitOpsFeature FlagsA/B TestingNo Server RequiredTypeScript SDKYAML as Source of Truth
1. What is Featurevisor
Featurevisor is an open-source feature management system built around one radical idea:
your feature flags live in Git, not in a database.
All configuration is defined in YAML files, committed to version control, built into JSON datafiles,
and served from a CDN. SDKs read the datafile locally — no API call needed at evaluation time.
🌿
Git as Source of Truth
GitOps-first approach
All features, segments, and rules are YAML files in a Git repo. Every change is a commit with a PR, review, and audit history built in.
⚡
Zero-latency Evaluation
Client-side, local SDK
SDKs download one JSON datafile at startup. Flag evaluation is pure in-memory computation — no network round-trips per evaluation.
🏗️
No Server Required
Serve from any CDN
Built datafiles are static JSON. Serve from S3, CloudFront, Nginx, GitHub Pages — no dedicated flag server to run or maintain.
🧪
A/B Testing Built-in
Experimentation native
Supports bucketing, traffic allocation, multi-variant experiments, and sticky assignment — all defined in YAML alongside feature flags.
🔐
Type-safe & Validated
Schema validation on build
All YAML files are validated against JSON Schema at build time. Invalid configs fail CI — broken flags can never reach production.
🔄
Multi-environment
staging / production / custom
One YAML file defines rules per environment. Build produces separate datafiles per environment, deployed independently.
2. The GitOps Pattern — Core Idea
The Fundamental Shift
Traditional feature flag tools: UI → Database → API Server → SDK (4 hops, server dependency, network latency).
Featurevisor: YAML in Git → Build → JSON on CDN → SDK reads locally (zero runtime hops after initial download).
What GitOps means for feature flags
GitOps is the practice of using Git as the single source of truth for declarative infrastructure and application config. Featurevisor applies this to feature management:
Change goes through normal code review. Teammates can see exactly what changed. Required approvals enforced by GitHub/GitLab branch protection rules.
3
CI Validates & Builds
featurevisor build runs in CI. Validates schemas, resolves dependencies, compiles datafiles per environment. Fails fast on errors.
4
Deploy to CDN
Built JSON files are uploaded to S3/CDN/Nginx. SDKs poll for updates (configurable interval). No server restart needed.
5
SDK Evaluates Locally
SDK has the datafile in memory. sdk.isEnabled("checkout_v2", { userId }) is pure in-memory computation — nanoseconds, always available.
GITOPS FLOW ARCHITECTURE
Why this is powerful: The CDN and SDK are the only runtime components. Even if your Git server, CI system, and build pipeline all go down, your SDKs keep serving flags correctly because the datafile is cached in memory.
3. Core Concepts
Featurevisor has four building blocks. They compose together: Features reference Segments, Segments use Attributes, Datafiles bundle everything.
🏷️
Attributes
Properties about a user or context
Atomic properties you know about the current user or environment. Used as inputs to segment conditions.
userId, email, country, plan, deviceType
Typed: string, boolean, integer, double, date
Capture flag = include in analytics events
👥
Segments
Named groups of users
Boolean conditions on attributes that define a user group. Reusable across many features.
Combine attributes with AND / OR / NOT
Operators: equals, contains, startsWith, gt, lt…
Example: premium_eu = plan=premium AND country=EU
🚩
Features
The actual flags
Declare ON/OFF flags, multi-variant experiments, or config values. Rules determine which segment sees which value.
Variables: typed configuration per variation
Traffic allocation: percentage-based bucketing
Environment overrides per env block
📦
Datafiles
The compiled output
Build-time output: one JSON file per environment, per tag group. This is what SDKs download and cache.
Contains only features/segments relevant to tag
Includes revision number for cache busting
Immutable once built — safe for aggressive CDN caching
4. YAML File Structure — Full Examples
Define every property you can know about a user or request context.
# attributes/userId.ymltype: stringdescription: "Unique user identifier"capture: true# include in analytics events---# attributes/plan.ymltype: stringdescription: "Subscription plan: free | starter | pro | enterprise"capture: false---# attributes/country.ymltype: stringdescription: "ISO 3166-1 alpha-2 country code"---# attributes/deviceType.ymltype: string# "mobile" | "desktop" | "tablet"---# attributes/accountAge.ymltype: integer# days since registration
Reusable user groups composed from attribute conditions.
The most important file — defines the flag, its variations, variables, and rollout rules per environment.
# features/new_checkout.ymldescription: "New checkout flow with saved cards"tags: ["checkout", "payments"] # used for datafile grouping# Variables = typed config values per variationvariablesSchema:
- key: buttonColortype: stringdefaultValue: "blue"- key: maxSavedCardstype: integerdefaultValue: 3- key: showExpressCheckouttype: booleandefaultValue: false# Variations (for A/B testing)variations:
- value: "control"# old checkoutweight: 50# 50% of traffic- value: "treatment"# new checkoutweight: 50variables: # override defaults for this variation- key: buttonColorvalue: "green"- key: maxSavedCardsvalue: 5- key: showExpressCheckoutvalue: true# Bucketing key: what determines which bucket a user falls intobucketBy: userId# sticky per user# Rules per environmentenvironments:
staging:
rules:
- key: "all_staging"segments: "*"# everyone in stagingpercentage: 100production:
rules:
- key: "premium_early_access"segments: premium_users# segment namepercentage: 100- key: "gradual_rollout"segments: "*"percentage: 20# 20% of all other users
// featurevisor.config.js — project configurationmodule.exports = {
projectRootPath: __dirname,
// Where YAML files liveattributesDirectoryPath: "./attributes",
segmentsDirectoryPath: "./segments",
featuresDirectoryPath: "./features",
// Output directory for built datafilesoutputDirectoryPath: "./dist",
// Environments — one datafile per environmentenvironments: ["staging", "production"],
// Tags — group features into separate datafiles for different appstags: ["checkout", "onboarding", "admin", "mobile"],
// Revision format in built datafilesrevision: "git", // uses git short SHA
};
// Produces: dist/staging/datafile-tag-checkout.json// dist/staging/datafile-tag-onboarding.json// dist/production/datafile-tag-checkout.json// dist/production/datafile-tag-onboarding.json
PR Review as the approval gate: You can require featurevisor lint as a required CI check. This means no broken feature flag config can merge to main — the same workflow engineers already use for code review.
6. SDK Integration
The SDK downloads the datafile and evaluates flags entirely in-process. There is no per-evaluation network call.
import { createInstance } from"@featurevisor/sdk";
// Create SDK instance — downloads datafile onceconst sdk = createInstance({
// URL of compiled datafile for this environment + tag group
datafileUrl: "https://cdn.example.com/production/datafile-tag-checkout.json",
// How often to refresh (milliseconds). 0 = no polling.
refreshInterval: 30_000, // 30 seconds// Called when a new datafile version is fetched
onRefresh: () => console.log("flags refreshed"),
// Optional: initial datafile (for SSR / edge hydration)
datafile: window.__FEATUREVISOR_DATAFILE__,
// Sticky bucketing: remember which bucket user was in
stickyFeatures: {
"new_checkout": { variation: "treatment" }
},
});
// Await initial datafile loadawait sdk.onReady();
Sticky by design: Same userId always hashes to the same bucket. No session storage, no cookie needed. The same user sees the same variation across devices.
// In your analytics / event tracking codeconst variation = sdk.getVariation("homepage_hero", context);
const heroTitle = sdk.getVariableString("homepage_hero", "heroTitle", context);
// Send to analytics (Mixpanel, Amplitude, Segment, etc.)
analytics.track("experiment_viewed", {
experiment: "homepage_hero",
variation: variation, // "control" | "v1" | "v2"
userId: context.userId,
});
// Set as user property for cohort analysis
analytics.identify(context.userId, {
`experiment_homepage_hero`: variation,
});
// Later: query your analytics tool for// conversion rate by experiment_homepage_hero property
Note: Featurevisor does NOT have a built-in analytics dashboard. It's responsible for flag evaluation only. You integrate with your own analytics tool (Mixpanel, Amplitude, PostHog, Segment) to track and analyze experiment results.
8. Rollout Strategies
🎯
Segment-first Rollout
Enable only for specific segment first, expand later. Classic beta / early access pattern.
dist/
├── development/
│ ├── datafile-tag-ui.json
│ └── datafile-tag-checkout.json
├── staging/
│ ├── datafile-tag-ui.json
│ └── datafile-tag-checkout.json
└── production/
├── datafile-tag-ui.json
└── datafile-tag-checkout.json
Each JSON file contains:
{
"schemaVersion": "1",
"revision": "abc1234", // git SHA
"attributes": [...],
"segments": [...],
"features": [...] // only features with matching tag
}
Tags = code splitting for flags: A mobile app only downloads the datafile-tag-mobile.json, not the 200 checkout flags it doesn't need. Keeps the payload small.
10. Evaluation Engine — How Decisions Are Made
Understanding the evaluation order is critical for debugging unexpected flag behavior.
EVALUATION DECISION TREE
Rule evaluation is first-match-wins
// If you have these rules:rules:
- key: "enterprise"segments: enterprise_userspercentage: 100← checked FIRST- key: "general"segments: "*"percentage: 10← only checked if enterprise rule didn't match// Enterprise user → matched rule 1 → always enabled (100%)// Free user → skipped rule 1 → checked rule 2 → 10% chance enabled
11. Featurevisor vs Unleash vs LaunchDarkly
Aspect
Featurevisor
Unleash
LaunchDarkly
Source of truth
Git (YAML)
Database (Postgres)
Proprietary cloud DB
Change audit trail
Git history — automatic
Change log in DB
Audit log in UI
Review workflow
PR-based code review
UI with role-based access
UI with approval workflows ($)
Runtime infrastructure
CDN only
Server + DB + Unleash Edge
LaunchDarkly SaaS
Evaluation location
100% client-side (in SDK)
Server-side or client-side
Server-side or client-side
Evaluation latency
~0ms (in-memory)
<1ms local, ~5ms remote
<1ms local, ~20ms remote
Real-time updates
Polling interval (30–60s)
WebSocket / SSE push
Streaming (SSE) push
Non-technical users
Hard (YAML + PR required)
Good (UI available)
Excellent (UI + workflows)
SDK ecosystem
JS / TS / React / Node (limited)
30+ languages
30+ languages
Analytics integration
BYO analytics
Impression data API
Built-in experiments UI ($)
Cost
Free / self-hosted
Free OSS / paid cloud
Paid SaaS ($$$)
Best for
Engineering-led teams, GitOps shops
Teams wanting UI + code balance
Enterprise, product/non-tech teams
12. Trade-offs — Honest Assessment
Strengths
✓
Audit trail is free
Git blame, PR history, diff view — you know exactly who changed what flag, when, and why (PR description).
✓
No server to run
Zero operational burden at evaluation time. CDN uptime SLA is typically 99.99%+. No flag server to page you at 3am.
✓
Works offline
Once the datafile is in SDK memory, flags keep working even if your CDN is down.
✓
Fits existing workflows
PRs, reviews, CI checks — same tools engineers already use. No new tool to learn.
✓
Validated config
Schema validation means you can never deploy a broken flag silently. CI catches it.
Weaknesses
✗
No instant toggle
Turning off a flag requires a Git commit → CI → CDN deploy. Minimum ~2–5 minutes even with optimized CI.
✗
Engineers only
Product managers and non-engineers cannot change flags without a developer or learning Git + YAML.
✗
No push updates
SDK polling means up to 30–60 seconds before a flag change propagates. Not suitable for true real-time emergency shutoffs.
✗
JS-ecosystem focused
Official SDKs are TypeScript/React/Node. Other languages need community SDKs or manual datafile parsing.
✗
No built-in analytics
You must implement your own experiment tracking and analysis. More flexibility, but more work.
When NOT to use Featurevisor: If you need non-engineers to toggle flags independently without developer involvement, or if you need sub-second flag changes in production emergencies, a traditional flag server (Unleash, LaunchDarkly) is a better fit.
Use snake_case for feature keys: new_checkout_flow
2
Prefix features with domain: checkout_, onboarding_
3
Always add description field — it becomes documentation
4
Tag features by team or product area for separate datafiles
5
Use meaningful rule keys: "beta_users" not "rule_1"
6
Keep bucketBy: userId as default — ensures sticky user experience
Operational Tips
✓
Set CDN Cache-Control: max-age=30 — short TTL for fast propagation
✓
Include revision in analytics events to correlate experiments with deployments
✓
Use featurevisor test to write unit tests for feature rules before merging
✓
Archive old features instead of deleting — preserves experiment history in git
✓
Monitor datafile size — if it grows >200KB, split tags more aggressively
✓
Use onRefresh callback to emit a metric when SDK downloads a new datafile
Testing Feature Rules with the CLI
# features/new_checkout.tests.yml — co-located test filefeature: new_checkoutassertions:
# Premium user in production should be in treatment- description: "Premium user gets new checkout"environment: productionat: 40# bucket position (0-100)context:
userId: "user_abc"plan: "pro"expectedToBeEnabled: trueexpectedVariation: "treatment" # Free user not in premium segment- description: "Free user in 20% rollout at bucket 15"environment: productionat: 15context:
userId: "user_xyz"plan: "free"expectedToBeEnabled: true# bucket 15 < 20% rule# Run: npx featurevisor test# ✓ Premium user gets new checkout# ✓ Free user in 20% rollout at bucket 15
The GitOps Feature Flag Mental Model
Think of Featurevisor as infrastructure-as-code for your feature flags. Just as Terraform stores cloud infrastructure in Git and builds plans before applying, Featurevisor stores feature configuration in Git and builds datafiles before deploying. The same benefits apply: version control, code review, automated validation, and a complete audit trail — with zero additional tooling for teams already using Git-based workflows.