The GitOps Standard for Feature Flags & Application Configuration
FlagWay is an source-available platform that treats Feature Flags and Application Configuration as Infrastructure-as-Code.
It eliminates the two biggest risks in modern software delivery:
- Zombie Feature Flags (Technical Debt that causes outages).
- Configuration Drift (Dev/Prod mismatches that cause bugs).
Instead of managing flags in a dashboard (ClickOps), you define them in Git. FlagWay enforces their lifecycle during the build and syncs them to your runtime (LaunchDarkly, Split, etc.) via Kubernetes.
Modern development has a "State" problem. While we version control our Code and our Infrastructure (Terraform), we treat Application State (Feature Flags & Configs) as second-class citizens.
Developers wrap code in a flag for a 2-week experiment. Two years later, the flag is still there.
- Result: The codebase becomes a graveyard of dead paths. Testing complexity explodes (2^n states).
- The Horror Story: A developer deletes the flag from the provider UI, but forgets to remove the
if (flags.isEnabled("x"))code. The app crashes in Production.
A developer enables a feature in the Development environment but forgets to enable it in Production.
- Result: The feature works on
localhostbut fails for customers. - The Horror Story: A critical security patch is behind a flag. It is "On" in QA, but accidentally "Off" in Prod.
As teams adopt GitOps for configuration, they create one YAML file per property. A microservice with 100 configs = 100 files.
- Result: Repository clutter, hard to navigate, difficult to maintain related configs together.
- The Horror Story: Database configs are scattered across 5 files. A developer updates the hostname but forgets the port. Connection fails in production.
Feature flag tools assume dev/staging/prod. But enterprises use SIT/UAT/PREPROD/PROD or CTE/RC/MAINT.
- Result: Teams can't adopt tools that hardcode environment names.
- The Horror Story: Your bank uses "RC" (Release Candidate). The tool only knows "staging". You build custom workarounds or abandon the tool.
FlagWay introduces a strict "Shift Left" philosophy using five atomic components.
Flags are no longer database rows. They are Kubernetes Custom Resources (CRDs) stored in your Git repository.
# migrations/feat_checkout.yaml
apiVersion: flagway.io/v1alpha1
kind: Flag
metadata:
name: feat-new-checkout
spec:
key: "feat-new-checkout"
owner: "team-payments"
lifecycle:
state: "active"
# THE KILLER FEATURE: The Time Bomb
cleanup_deadline: "2026-05-10"
environments:
dev: { enabled: true }
prod: { enabled: false }Instead of 100 YAML files for 100 configs, group related properties in a single file.
# config/database.yaml
apiVersion: flagway.io/v1alpha1
kind: PropertyGroup
metadata:
name: database-config
spec:
owner: team-platform
lifecycle:
state: active
properties:
- key: db.url
type: URL
values:
dev: jdbc:postgresql://localhost:5432/myapp
prod: jdbc:postgresql://prod-db.aws.amazon.com:5432/myapp
- key: db.pool.size
type: Integer
values:
default: 10 # Used for dev, staging
prod: 50 # Production override
- key: db.ssl.enabled
type: Boolean
values:
default: true # All environments use SSLResult: Related configs stay together. Default values reduce duplication.
Define your environment names in .flagway.yaml. FlagWay adapts to your company.
# .flagway.yaml (project root)
project:
name: billing-service
# DEFINE YOUR WORLDS HERE
environments:
- name: "local"
required: false # It's okay if a flag/prop is missing for local
- name: "sit"
required: true # Build FAILS if a property is missing for SIT
aliases: ["test", "qa"] # (Optional) Allow these keys to map to SIT
- name: "uat"
required: true
aliases: ["staging", "acceptance"] # Multiple aliases per environment
- name: "preprod"
required: true
aliases: ["rc", "maint"]
- name: "prod"
required: true
protected: true # Enforces stricter validation rules (e.g., no localhost)Resolution Order:
- Exact match:
prod - Alias:
testβsit,stagingβuat - Default fallback: uses
defaultkey - Error: if required but missing
Result: Works with any company environment taxonomy. No hardcoded assumptions.
A Maven/Gradle plugin that runs Local Static Analysis (AST) on your source code. It blocks the build if you violate hygiene rules.
Rule A (Expiration): If Today > cleanup_deadline, the build FAILS. You must remove the flag or extend the date.
Rule B (The Tombstone): If you mark a flag as state: archived in YAML, but the code still contains flags.isEnabled("feat-new-checkout"), the build FAILS.
Rule C (Required Environments): If .flagway.yaml marks an environment as required: true, all properties must define values for it. Build fails otherwise.
Value: You cannot accidentally delete a flag definition while code still depends on it.
A Kubernetes Operator that watches your Git repository (via CRDs) and reconciles the state with your Feature Flag Provider (e.g., LaunchDarkly).
Logic: Git State == Real World State.
Drift Detection: If a user manually changes a flag in the LaunchDarkly UI, the Operator detects the drift and reverts it (or alerts, depending on policy).
- Java 21+
- Maven 3.9+
- Kubernetes Cluster (Minikube or Cloud)
Add the plugin to your project's pom.xml.
<plugin>
<groupId>io.flagway</groupId>
<artifactId>flagway-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<migrationsDir>src/main/resources/migrations</migrationsDir>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>Create a file src/main/resources/migrations/my_feature.yaml:
apiVersion: flagway.io/v1alpha1
kind: Flag
metadata:
name: my-feature
spec:
key: "my-feature"
lifecycle:
state: "active"
cleanup_deadline: "2026-12-31" # Set this date!mvn flagway:checkIf the date is in the past: The build will fail.
If the flag is archived but used in code: The build will fail.
graph TD
A["Flag YAML"] --> B["YamlParser"]
B --> F["ValidationPipeline"]
F --> C["UnifiedFlagValidator"]
F --> EV["EnvironmentValidator"]
C --> D["JavaParserScanner (AST)"]
C --> E["PolicyEngine (14 operators)"]
F --> K["FlagWayCLI"]
K --> G["SarifReporter"]
K --> L["Text/JSON Output"]
G --> I["SARIF 2.1.0 Report"]
F --> H["BasicReaper"]
H --> J["Cleanup Actions"]
Note
UnifiedFlagValidator is the primary validator covering all 4 violation types: TIME_BOMB, TOMBSTONE, DEPRECATED, OVERDUE.
| Module | Description |
|---|---|
flagway-api |
The Core. Shared Data Model (Flag, PropertyGroup, ProjectConfig) and YAML Parsers. |
flagway-core |
The Logic Engine. UnifiedFlagValidator, ValidationPipeline, PolicyEngine, JavaParserScanner, SarifReporter. |
flagway-cli |
The CLI. Standalone validator with text, JSON, and SARIF output formats. |
flagway-maven-plugin |
The Reaper (Maven). Build-time enforcer with AST analysis. Validates required environments from .flagway.yaml. |
flagway-gradle-plugin |
The Reaper (Gradle). Same enforcement as Maven plugin, for Gradle projects. |
flagway-benchmarks |
Performance. JMH benchmarks for validation throughput. |
flagway-test |
The Test Kit. JUnit 5 extension for declarative, parallel-safe flag overrides with annotation and programmatic APIs. |
flagway-enterprise |
Enterprise Features. License validation, snooze capabilities, audit logging. |
flagway-dist |
Distribution. Packaging scripts for CE and Pro editions. |
| Feature | Description | Status |
|---|---|---|
| Environment Coverage | Ensures all required environments have values | β Complete |
| PropertyGroup Validation | Validates grouped configuration properties | β Complete |
| Default Fallback | Supports default value for all environments |
β Complete |
| Environment Aliases | Map custom names (sit, uat) to environments |
β Complete |
| Lifecycle Enforcement | TOMBSTONE + OVERDUE + DEPRECATED detection | β Complete |
| AST-Based Scanning | JavaParser for accurate flag usage detection | β Complete |
| Intelligent Caching | File-level caching (~80% hit rate) | β Complete |
| Actionable Errors | File:line context + fix options | β Complete |
| Structured Logging | SLF4J with operation tags | β Complete |
| Null Safety | Defensive validation on all public APIs | β Complete |
| Category | Operators | Count | Status |
|---|---|---|---|
| Pattern Matching | contains, notContains, startsWith, endsWith, regex |
5 | β Complete |
| Environment Comparison | notSameAs (prod β dev) |
1 | β Complete |
| Data Validation | oneOf, minLength, maxLength, exactLength, range |
5 | β Complete |
| Type Validation | isValidUrl, isValidJson, isValidEmail, isNumeric |
4 | β Complete |
| Conditional Rules | requiresIf |
1 | β Complete |
| Total Operators | 14 | β Production Ready |
| Use Case | Implementation | Example |
|---|---|---|
| No Localhost in Prod | contains + deny |
Block localhost, 127.0.0.1 |
| HTTPS Enforcement | startsWith + allow |
Require https:// URLs |
| Secret Detection | regex + deny |
Block hardcoded API keys (Stripe, AWS, GitHub) |
| Prod β Dev | notSameAs + enforce |
Prevent configuration copy-paste |
| Enum Validation | oneOf + enforce |
Restrict database types |
| Range Validation | range + enforce |
Connection pool limits (10-100) |
| URL Format | isValidUrl + enforce |
RFC 3986 validation |
| Email Format | isValidEmail + enforce |
RFC 5322 validation |
| Feature | Description | Status |
|---|---|---|
| Target Key Filtering | Wildcard patterns (*.url, db.*) |
β Complete |
| Policy Exceptions | Opt-out via ignorePolicies |
β Complete |
| Multi-Policy Enforcement | Layer multiple policies per property | β Complete |
| Actionable Error Messages | Build failures with fix suggestions | β Complete |
| Integration Testing | 321+ total tests (unit + integration) | β Complete |
| Resource | Description | Status |
|---|---|---|
| Operator Reference | All 14 operators with examples | β
docs/POLICY_OPERATORS.md |
| Best Practices Guide | Patterns, troubleshooting, migration | β
docs/POLICY_BEST_PRACTICES.md |
| Demo Configuration | 9 production-ready policies | β
samples/flagway-demo/.flagway.yaml |
FlagWay Community Edition is licensed under the ****.
Enterprise features require a commercial license.
"Stop managing flags with hope. Manage them with Code."