Skip to main content

Harden your workflow

You finished the quickstart. You have one TOML file, a flag, and an eval_string call site. That's enough to ship — for a side project. Six chapters turn it into a reviewable, testable, observable change process you can take to production.

The thread through all six is one realistic flag — a three-variant string with a percentage-bucketed A/B/C rollout, scoped to US users only. Every chapter operates on the same flag, so once you've finished one chapter, the next one picks up where you left off.

Chapters

  1. Define the flag namespace. Write a realistic flag with three variants, three bucket segments, and a US-only geo gate. Run exd explain once to verify the whole shape — variants, rule walk, segment tree, required context, pitfalls — before another tool touches it.

  2. Lint on every commit and every PR. Wire exd lint into a pre-commit hook and a GitHub Actions workflow. Typos, dangling segment references, and shape errors get caught before the diff reaches a reviewer.

  3. Schema-driven application code. Run exd schema to learn what context the flag reads, codegen a typed context struct, and write the eval call site. Add a one-line validate_context test so the application and the manifest cannot drift apart silently.

  4. Fixtures and automated tests. Run exd fixtures to generate a (ctx, expected variant) table from the rule chain. Eyeball it for correctness, commit it, and consume it from a fixture-driven test that runs on every cargo test / npm test.

  5. Roll out with the testing attribute. Walk a flag through Disabled → Testing → Enabled. While testing = true is on, only callers that pass include_testing see the new rules — so dev and admin can run end-to-end tests in production while regular traffic still sees the off variant. Drop the gate when you're happy; the rules go live.

  6. Troubleshoot with exd eval. "Why did user u_123 get the off variant last night?" Reconstruct the evaluation with exd eval --trace, layer exd explain --ctx for counterfactuals, and walk through the common diagnostic patterns (missing bucketing attribute, wrong env, predicate-type mismatch).

Prerequisites

  • Quickstart complete: marketing/flags/welcome-banner.toml exists, your Rust or TS code evaluates it.
  • The exd CLI on PATH: cargo install exd-client (one binary; used by both Rust and TS projects).
  • A git repo. The pre-commit hook and CI examples assume it.

Where everything sits

A flag namespace is a directory whose name is the namespace slug, holding flags/ and segments/ inside it (see docs/reference/manifest/01-directory-layout.md). When you colocate flags with an application, the namespace directory sits as a child of the application repo — never as the repo:

<your-app-repo>/ # application repo root (name is yours; not the slug)
├── marketing/ # flag namespace; slug = "marketing"
│ ├── flags/
│ │ └── welcome-banner.toml
│ └── segments/
│ ├── welcome-banner-bucket-control.toml
│ ├── welcome-banner-bucket-treat-a.toml
│ └── welcome-banner-bucket-treat-b.toml
├── src/ # your application source
│ └── ...
├── tests/
└── .git/

The directory name (marketing/) is the namespace slug — exd infers it directly, so no namespace.toml is needed at this stage. All exd commands point at the namespace directory, not the repo root — exd lint marketing/ from the repo root, or cd marketing/ && exd lint . if you prefer.

Once a second service needs the same flags, the marketing/ directory lifts cleanly out of the app repo into a dedicated feature-flags repo — see Centrally hosted flag namespace. The migration is a literal git subtree split --prefix=marketing; the file contents stay the same.

Where to go next