Skip to content

Terraform Provider

The Featureflip Terraform provider manages your flag configuration as code through the Management API: projects, environments, feature flags (including variations and per-environment targeting), user segments, SDK keys, and outbound webhooks.

It is published as canopy-labs/featureflip on both the Terraform Registry and the OpenTofu Registry, and developed in the open at canopy-labs/terraform-provider-featureflip.

terraform {
required_providers {
featureflip = {
source = "canopy-labs/featureflip"
version = "~> 0.1"
}
}
}
provider "featureflip" {
organization = "acme-corp"
# token via FEATUREFLIP_TOKEN environment variable (recommended),
# or: token = var.featureflip_token
}

The installation block above works with OpenTofu as written. Run tofu init and OpenTofu fetches canopy-labs/featureflip from its own registry (the same release files the Terraform Registry serves) and verifies the download against the Canopy Labs signing key. Wherever this page says terraform, type tofu and keep the same arguments, tofu import included.

Create an API token in the Featureflip dashboard — tokens cannot be created through the public API:

  • Service token (ffs_…) — recommended. Organization Settings → Service Tokens. Scoped to one organization with a role and an optional project allowlist. Use Member or Admin. Viewer tokens cannot write, and webhooks need Admin.
  • Personal access token (ffp_…). Acts as your user across your organizations.

Prefer the FEATUREFLIP_TOKEN environment variable over putting the token in configuration. organization and base_url can likewise be set via FEATUREFLIP_ORGANIZATION and FEATUREFLIP_BASE_URL.

resource "featureflip_project" "web" {
key = "web"
name = "Web App"
description = "Customer-facing web application"
}
# Boolean flags get true/false variations automatically.
resource "featureflip_feature_flag" "new_checkout" {
project = featureflip_project.web.key
key = "new-checkout"
name = "New Checkout Flow"
type = "Boolean"
tags = ["checkout"]
}
# Non-Boolean flags declare their variations inline.
resource "featureflip_feature_flag" "banner_text" {
project = featureflip_project.web.key
key = "banner-text"
name = "Banner Text"
type = "String"
variations = [
{ key = "control", name = "Control", value = "Welcome!" },
{ key = "variant", name = "Variant", value = "Hi there!" },
]
}

featureflip_flag_environment manages a flag’s state and targeting in a single environment. List position is rule priority:

resource "featureflip_flag_environment" "new_checkout_prod" {
project = featureflip_project.web.key
flag = featureflip_feature_flag.new_checkout.key
environment = "production"
enabled = true
default_variation = "false"
rules = [
{
description = "Beta users always get the new checkout"
variation = "true"
segment = featureflip_segment.beta_users.key
},
{
description = "50% rollout in Germany"
variation = "true"
rollout_percentage = 50
condition_groups = [
{
operator = "And"
conditions = [
{ attribute = "country", operator = "Equals", values = ["DE"] },
]
},
]
},
]
}

featureflip_webhook subscribes an HTTPS endpoint to configuration changes, so the receiver that reacts to a toggle is declared in the same place as the flag. It needs provider 0.3.0 or later and an Admin token:

resource "featureflip_webhook" "deploys" {
name = "Deploy pipeline"
url = "https://ci.example.com/hooks/featureflip"
event_types = ["flag.toggled", "flag.environment_config.updated"]
project_ids = [featureflip_project.web.id]
environment_ids = [featureflip_environment.production.id]
}
output "webhook_signing_secret" {
value = featureflip_webhook.deploys.secret
sensitive = true
}

Leave out event_types, project_ids or environment_ids and the subscription covers everything in that dimension. Scopes take ids rather than keys, which is why the example passes .id. The featureflip_webhook_event_types data source returns the full list of event types if you want to build a filter from it.

To rotate the signing secret, add a featureflip_webhook_secret. Featureflip signs every delivery with every active secret, so your receiver can switch to the new one while the old one still works. When it has, bring the original secret under Terraform with an import block pointing at the webhook’s secret_id, then delete that resource in a later apply to retire it. The registry docs walk through the three steps.

ResourceManages
featureflip_projectA project
featureflip_environmentAn environment within a project
featureflip_feature_flagA flag and its variations
featureflip_flag_environmentA flag’s per-environment state and targeting rules
featureflip_segmentA reusable user segment
featureflip_sdk_keyAn SDK key (destroying it revokes the key)
featureflip_webhookAn outbound webhook subscription
featureflip_webhook_secretAn extra signing secret on a webhook, for rotation (destroying it retires the secret)

Data sources exist for reading an existing featureflip_organization, featureflip_project, featureflip_environment, featureflip_feature_flag, and featureflip_segment. featureflip_webhook_event_types lists the event types a webhook can subscribe to.

Every resource supports terraform import, so you can adopt flags that already exist:

Terminal window
terraform import featureflip_feature_flag.new_checkout web/new-checkout

It manages flag configuration, not flag state. The provider owns which flags exist, their variations, and their targeting rules. It is not built for flipping a flag on and off during an incident: that is a dashboard or API action, and a Terraform apply is a slower path to it. A common pattern is to manage projects, environments, flags, and segments in Terraform while leaving day-to-day toggling to the dashboard.

rules is authoritative. Once you set rules on a featureflip_flag_environment, Terraform owns every rule in that flag-environment, and rules added in the dashboard are removed on the next apply. Destroying the resource deletes the managed rules and disables the flag in that environment, leaving the fallthrough configuration in place.

SDK keys are sensitive, and destroying one revokes it. The plaintext value of a featureflip_sdk_key is only available at creation and is stored in Terraform state, so protect your state. Destroying the resource revokes the key, which cannot be undone. Imported keys cannot recover their plaintext.

Webhook signing secrets follow the same rule. The secret a webhook is created with, and each featureflip_webhook_secret, is readable once and then kept only in your state. A subscription always keeps at least one active secret. If removing a featureflip_webhook_secret would retire the last one, the provider leaves it active, drops it from state and says so in a warning.

An auto-disabled webhook comes back on at the next apply. Featureflip switches a subscription off after 20 failed delivery rounds in a row. Because enabled defaults to true, the next plan shows it changing back, and applying turns deliveries on again. Fix the receiver before you apply, or set enabled = false until you have.

Full resource and data-source documentation, including every argument and attribute, is published on the Terraform Registry.

For a worked walkthrough covering install, a first project and flag, importing flags you already have, and where to stop putting flag config in code, see Feature Flags as Code: Managing Featureflip with Terraform.

For the process around the provider, including what to look for when reviewing a flag diff, how to structure the plan and apply jobs, and how to handle configuration drift after an incident, see GitOps for feature flags.