rollfuse
← Back to tutorials

Create a feature flag and read its value from your app

This walks through the full loop for a new flag: create it with its variations, configure it for one environment, then evaluate it from application code.

1. Create the flag with its variations

A feature flag belongs to a project, not to a single environment, and it's created together with its variations: POST /v1/projects/{project_id}/feature-flags requires at least two.

const res = await fetch(
  `https://api.rollfuse.com/v1/projects/${projectId}/feature-flags`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "New Checkout Flow",
      key: "new-checkout-flow",
      variations: [
        { key: "on", value: true },
        { key: "off", value: false },
      ],
    }),
  }
);
const flag = await res.json();
console.log(flag.id, flag.key);
// flag.variations = [{ id, key: "on", value: true }, { id, key: "off", value: false }]

token here is a session token or an API key with a role that has permission to manage feature flags on the project. key is what your application code references when evaluating the flag; each variation's id is what the environment config below points at.

At this point the flag exists but has no per-environment configuration, so evaluating it anywhere would fall back to whatever value your evaluation call passes in.

2. Turn it on for one environment

Flags are configured per environment, so a flag can be live in staging and untouched in production at the same time. Set (or replace) that config with PUT /v1/environments/{environment_id}/feature-flags/{feature_flag_id}/config, pointing default_variation_id at the variation returned for "on":

const onVariationId = flag.variations.find((v) => v.key === "on").id;

const configRes = await fetch(
  `https://api.rollfuse.com/v1/environments/${environmentId}/feature-flags/${flag.id}/config`,
  {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      enabled: true,
      default_variation_id: onVariationId,
      rules: [],
    }),
  }
);
const config = await configRes.json();

This is a PUT, not a PATCH: it replaces the flag's config for this environment wholesale, including its rules. An empty rules array means every subject gets default_variation_id. If you later add targeting rules or a percentage rollout on top of this config, you'll be updating this same resource, not creating a new one.

3. Read the flag from application code

Evaluation happens through @rollfuse/sdk-js, which reads from a synced local snapshot rather than making a REST call per evaluation:

import { RollfuseClient } from "@rollfuse/sdk-js";

const client = new RollfuseClient({
  baseUrl: "https://api.rollfuse.com",
  credential: process.env.ROLLFUSE_CREDENTIAL!, // set before running
});
await client.start();

const result = client.evaluate("user-42", "new-checkout-flow", {
  attributes: { plan: "pro" },
  fallback: false,
});

console.log(result.value); // true, once the environment config above is live
console.log(result.reason); // why this value was returned
console.log(result.variation_key); // "on"

credential here is an SDK-specific environment credential, separate from the token used against the REST API in the previous two steps. The REST API is how you administer flags; the SDK is how your running application reads them.

If you need every flag's value for a given subject at once, instead of one flag at a time, use client.evaluateAll("user-42", { attributes: { plan: "pro" } }), which returns the same shape keyed by flag key.

Where to go next

Once a flag reads correctly at 100% in one environment, the next step is usually not "on for everyone at once": see the percentage rollout tutorial for how to ramp it up gradually with deterministic bucketing.