Skip to main content

Feature Flag Matrix

Generate per-plan feature flag bundles and a flattened environment-by-plan matrix from one typed model.

Source

examples/feature-flag-matrix/types.rank
pub Environment = `dev` | `staging` | `prod`

pub Plan = `free` | `pro` | `enterprise`

pub FlagState = `enabled` | `disabled`

pub FeatureFlags = Object {
auditLogs: FlagState,
sso: FlagState,
ledgerExport: FlagState,
prioritySupport: FlagState,
}

pub FlagMatrixEntry = Object {
environment: Environment,
plan: Plan,
flags: FeatureFlags,
}
examples/feature-flag-matrix/main.rank
/// Generates per-plan feature flag configs and a flattened matrix view.
/// Shows typed environment/plan combinations and multi-file emission.

use std::Emit
use std::Path
use std::collections::{ flatMap, map }
use root::types::{ Environment, FeatureFlags, FlagMatrixEntry, Plan }

environments: [Environment] = [`dev`, `staging`, `prod`]
plans: [Plan] = [`free`, `pro`, `enterprise`]

base_flags_for = |plan: Plan| -> FeatureFlags {
return match plan {
`free` => {
auditLogs: `disabled`,
sso: `disabled`,
ledgerExport: `disabled`,
prioritySupport: `disabled`,
},
`pro` => {
auditLogs: `enabled`,
sso: `disabled`,
ledgerExport: `enabled`,
prioritySupport: `disabled`,
},
`enterprise` => {
auditLogs: `enabled`,
sso: `enabled`,
ledgerExport: `enabled`,
prioritySupport: `enabled`,
},
}
}

flags_for = |environment: Environment, plan: Plan| -> FeatureFlags {
base = base_flags_for(plan)

return match environment {
`dev` => base with {
auditLogs: `enabled`,
ledgerExport: `enabled`,
},
`staging` => base,
`prod` => base,
}
}

entry_for = |environment: Environment, plan: Plan| -> FlagMatrixEntry {
return {
environment: environment,
plan: plan,
flags: flags_for(environment, plan),
}
}

matrix_entries = environments
|> flatMap(|environment: Environment| plans |> map(|plan: Plan| entry_for(environment, plan)))

plan_bundle_for = |plan: Plan| {
return {
plan: plan,
environments: environments |> map(|environment: Environment| {
environment: environment,
flags: flags_for(environment, plan),
}),
}
}

pub main = || Emit::manifest({
entries: [
{
path: Path::join([`flags`, `matrix.json`]),
format: `json`,
value: matrix_entries,
},
{
path: Path::join([`flags`, `free.json`]),
format: `json`,
value: plan_bundle_for(`free`),
},
{
path: Path::join([`flags`, `pro.json`]),
format: `json`,
value: plan_bundle_for(`pro`),
},
{
path: Path::join([`flags`, `enterprise.json`]),
format: `json`,
value: plan_bundle_for(`enterprise`),
},
]
})

Output

Running the example with --file-root writes:

  • flags/matrix.json
  • flags/free.json
  • flags/pro.json
  • flags/enterprise.json

Run it

npm run rank -- examples/feature-flag-matrix --file-root out/feature-flag-matrix

Key concepts

  • Typed environment and plan dimensions become a complete matrix with flatMap.
  • A shared feature model emits both per-plan bundles and a flattened aggregate view.
  • with lets one environment patch a base plan config without duplicating the whole object.