|
| 1 | +# Selectors |
| 2 | + |
| 3 | +Selectors are query expressions that allow you to filter flag configurations from flagd's sync service. They enable providers to request only specific subsets of flags instead of receiving all flags, making flagd more efficient and flexible for complex deployments. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +In flagd, **selectors** provide a way to query flags based on different criteria. This is particularly powerful because flagd decouples **flag sources** from **flag sets**, allowing for more granular control over which flags are synchronized and evaluated. |
| 8 | + |
| 9 | +### Key Concepts |
| 10 | + |
| 11 | +- **Flag Source**: Where flag configuration data comes from (file, HTTP endpoint, gRPC service, etc.) |
| 12 | +- **Flag Set**: A logical grouping of flags identified by a `flagSetId` |
| 13 | +- **Selector**: A query expression that filters flags by source, flag set, or other criteria |
| 14 | +- **Flag Set Metadata**: The selector information is "reflected" back in response metadata for transparency |
| 15 | + |
| 16 | +## Source vs Flag Set Decoupling |
| 17 | + |
| 18 | +### Before: Tight Coupling |
| 19 | + |
| 20 | +Historically, each source provided exactly one flag set, and providers had to target specific sources: |
| 21 | + |
| 22 | +```yaml |
| 23 | +# Old approach - targeting a specific source |
| 24 | +selector: "my-flag-source.json" |
| 25 | +``` |
| 26 | +
|
| 27 | +### After: Flexible Flag Sets |
| 28 | +
|
| 29 | +Now, sources and flag sets are decoupled. A single source can contain multiple flag sets, and flag sets can span multiple sources: |
| 30 | +
|
| 31 | +```yaml |
| 32 | +# New approach - targeting a logical flag set |
| 33 | +selector: "flagSetId=project-42" |
| 34 | +``` |
| 35 | +
|
| 36 | +## Flag Set Configuration |
| 37 | +
|
| 38 | +Flag sets are typically configured at the top level of a flag configuration, with all flags in that configuration inheriting the same `flagSetId`. This is the recommended approach for most use cases. |
| 39 | + |
| 40 | +### Set-Level Configuration |
| 41 | + |
| 42 | +The most common pattern is to set the `flagSetId` at the configuration level, where all flags inherit it: |
| 43 | + |
| 44 | +```json |
| 45 | +{ |
| 46 | + "metadata": { |
| 47 | + "flagSetId": "payment-service", |
| 48 | + "version": "v1.2.0" |
| 49 | + }, |
| 50 | + "flags": { |
| 51 | + "new-checkout-flow": { |
| 52 | + "state": "ENABLED", |
| 53 | + "variants": { |
| 54 | + "on": true, |
| 55 | + "off": false |
| 56 | + }, |
| 57 | + "defaultVariant": "on" |
| 58 | + }, |
| 59 | + "stripe-integration": { |
| 60 | + "state": "DISABLED", |
| 61 | + "variants": { "on": true, "off": false }, |
| 62 | + "defaultVariant": "off" |
| 63 | + } |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +In this example, both `new-checkout-flow` and `stripe-integration` flags belong to the `payment-service` flag set. |
| 69 | + |
| 70 | +### Metadata Inheritance and Override |
| 71 | + |
| 72 | +Flagd uses a hierarchical metadata system: |
| 73 | + |
| 74 | +1. **Set-Level Metadata**: Defined in the top-level `metadata` section, inherited by all flags |
| 75 | +2. **Flag-Level Metadata**: Defined in individual flag `metadata`, overrides set-level values for that flag |
| 76 | +3. **Merged Result**: Flag evaluations return merged metadata with flag-level taking precedence |
| 77 | + |
| 78 | +### Flag-Level Overrides (Advanced) |
| 79 | + |
| 80 | +For advanced use cases, individual flags can override the set-level `flagSetId`: |
| 81 | + |
| 82 | +```json |
| 83 | +{ |
| 84 | + "metadata": { |
| 85 | + "flagSetId": "payment-service", |
| 86 | + "team": "payments" |
| 87 | + }, |
| 88 | + "flags": { |
| 89 | + "standard-feature": { |
| 90 | + "state": "ENABLED", |
| 91 | + "variants": { "on": true, "off": false }, |
| 92 | + "defaultVariant": "on" |
| 93 | + // Inherits flagSetId: "payment-service" |
| 94 | + }, |
| 95 | + "experimental-feature": { |
| 96 | + "metadata": { |
| 97 | + "flagSetId": "experiments", // Override: belongs to different set |
| 98 | + "owner": "research-team" |
| 99 | + }, |
| 100 | + "state": "DISABLED", |
| 101 | + "variants": { "on": true, "off": false }, |
| 102 | + "defaultVariant": "off" |
| 103 | + } |
| 104 | + } |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | +In this example: |
| 109 | +- `standard-feature` inherits `flagSetId: "payment-service"` from set level |
| 110 | +- `experimental-feature` overrides to `flagSetId: "experiments"` |
| 111 | +- Both flags inherit `team: "payments"` (unless overridden at flag level) |
| 112 | +
|
| 113 | +## Flag Set Metadata "Reflection" |
| 114 | +
|
| 115 | +When you make a request with a selector, flagd "reflects" the selector information back in the response metadata. This provides transparency about what was actually queried and helps with debugging. |
| 116 | +
|
| 117 | +### Example |
| 118 | +
|
| 119 | +**Request with selector:** |
| 120 | +``` |
| 121 | +Selector: "flagSetId=project-42" |
| 122 | +``` |
| 123 | +
|
| 124 | +**Response includes reflected metadata:** |
| 125 | +```json |
| 126 | +{ |
| 127 | + "flags": { /* ... */ }, |
| 128 | + "metadata": { |
| 129 | + "flagSetId": "project-42" |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +This helps you: |
| 135 | +- Verify that your selector was parsed correctly |
| 136 | +- Debug complex selector queries |
| 137 | +- Understand exactly what flags were returned |
| 138 | +- Audit flag access patterns |
| 139 | + |
| 140 | +## Use Cases |
| 141 | + |
| 142 | +### Multi-Tenant Applications |
| 143 | + |
| 144 | +```yaml |
| 145 | +# Tenant A's flags |
| 146 | +selector: "flagSetId=tenant-a" |
| 147 | + |
| 148 | +# Tenant B's flags |
| 149 | +selector: "flagSetId=tenant-b" |
| 150 | +``` |
| 151 | +
|
| 152 | +### Environment Separation |
| 153 | +
|
| 154 | +```yaml |
| 155 | +# Development environment |
| 156 | +selector: "flagSetId=dev-features" |
| 157 | + |
| 158 | +# Production environment |
| 159 | +selector: "flagSetId=prod-features" |
| 160 | +``` |
| 161 | +
|
| 162 | +### Feature Team Isolation |
| 163 | +
|
| 164 | +```yaml |
| 165 | +# Payment team's flags |
| 166 | +selector: "flagSetId=payments" |
| 167 | + |
| 168 | +# User interface team's flags |
| 169 | +selector: "flagSetId=ui-components" |
| 170 | +``` |
| 171 | +
|
| 172 | +### Legacy Source-Based Selection |
| 173 | +
|
| 174 | +```yaml |
| 175 | +# Still supported for backward compatibility |
| 176 | +selector: "source=legacy-config.json" |
| 177 | +``` |
| 178 | +
|
| 179 | +## Best Practices |
| 180 | +
|
| 181 | +1. **Use Flag Sets for Logical Grouping**: Prefer `flagSetId` over `source` for new deployments |
| 182 | +2. **Plan Your Flag Set Strategy**: Design flag sets around logical boundaries (teams, features, environments) |
| 183 | +3. **Leverage Metadata**: Use metadata for debugging and auditing |
| 184 | +5. **Document Your Schema**: Clearly document your flag set naming conventions for your team |
| 185 | + |
| 186 | +## Migration Considerations |
| 187 | + |
| 188 | +The selector enhancement maintains full backward compatibility. See the [migration guide](../guides/migrating-to-flag-sets.md) for detailed guidance on transitioning from source-based to flag-set-based selection patterns. |
0 commit comments