Terraform Provider
Introduction
The ConfigDirector Terraform provider allows you to manage projects, environments, configs, tags, targeting rules, and segments via Terraform and OpenTofu.
To make the same changes from an AI coding assistant instead, see the MCP server.
Refer to the official ConfigDirector Terraform provider documentation for a full guide on all the features available in the provider.
Example
Here is a minimal example on how to use the provider:
terraform {
required_providers {
configdirector = {
source = "ConfigDirector/configdirector"
version = "~> 0.2"
}
}
}
provider "configdirector" {}
resource "configdirector_project" "example" {
name = "Targeting Rules Example"
slug = "targeting-rules-example"
}
resource "configdirector_config" "beta_features" {
project_id = configdirector_project.example.id
key = "beta-features"
role = "flag"
lifetime = "temporary"
type = "boolean"
initial_value = false
}
resource "configdirector_config_targeting_rules" "beta_features_test" {
project_id = configdirector_project.example.id
config_key = configdirector_config.beta_features.key
environment_slug = "test"
default_value = "false"
rules = [
{
id = provider::configdirector::rule_id("beta-features-test-named-testers")
type = "conditional"
order = 0
target = "value"
value = true
conditions = [
{
id = provider::configdirector::rule_id("beta-features-test-named-testers-identifier")
attribute = "identifier"
operator = "is one of"
targetType = "text"
targetValues = ["user-101", "user-202"]
}
]
}
]
}
resource "configdirector_config_targeting_rules" "beta_features_production" {
project_id = configdirector_project.example.id
config_key = configdirector_config.beta_features.key
environment_slug = "production"
default_value = "false"
rules = [
{
id = provider::configdirector::rule_id("beta-features-production-rollout")
type = "percentage"
order = 0
target = "percentage"
percentages = [
{
id = provider::configdirector::rule_id("beta-features-production-rollout-on")
percentage = 10
value = true
},
{
id = provider::configdirector::rule_id("beta-features-production-rollout-off")
percentage = 90
value = false
},
]
}
]
}
Segments
The configdirector_segment resource manages a segment, and is available from version 0.3.0 of the provider. groups holds the project definition as a list of condition groups, each a list of attribute conditions in the same shape as in targeting rules. overrides maps an environment id to that environment's own groups.
The resource owns every override of the segment: leaving overrides out, or removing an environment from it, removes that override. groups and overrides are sent as written and never read back, the same as the rules of configdirector_config_targeting_rules, so changes made outside Terraform do not show as drift.
A targeting rule uses the segment through a segment condition with kind = "segment", an operator of "in" or "not in", and the segment's id as segmentId. Continuing the example above:
resource "configdirector_environment" "staging" {
project_id = configdirector_project.example.id
name = "Staging"
slug = "staging"
color = "purple"
live = false
}
resource "configdirector_segment" "beta_testers" {
project_id = configdirector_project.example.id
key = "beta-testers"
name = "Beta testers"
groups = [
[
{
id = provider::configdirector::rule_id("beta-testers-acme-email")
attribute = "traits"
trait = "/email"
operator = "ends with any of"
targetType = "text"
targetValues = ["@acme.com"]
}
],
[
{
id = provider::configdirector::rule_id("beta-testers-opted-in")
attribute = "traits"
trait = "/betaOptIn"
operator = "equals"
targetType = "boolean"
targetValues = ["true"]
},
{
id = provider::configdirector::rule_id("beta-testers-app-version")
attribute = "appVersion"
operator = ">="
targetType = "semver"
targetValues = ["2.0.0"]
}
]
]
overrides = {
(configdirector_environment.staging.id) = [
[
{
id = provider::configdirector::rule_id("beta-testers-staging-named-users")
attribute = "identifier"
operator = "is one of"
targetType = "text"
targetValues = ["qa-user-1", "qa-user-2"]
}
]
]
}
}
resource "configdirector_config" "new_checkout_flow" {
project_id = configdirector_project.example.id
key = "new-checkout-flow"
role = "flag"
lifetime = "temporary"
type = "boolean"
initial_value = false
}
resource "configdirector_config_targeting_rules" "new_checkout_flow_production" {
project_id = configdirector_project.example.id
config_key = configdirector_config.new_checkout_flow.key
environment_slug = "production"
default_value = "false"
rules = [
{
id = provider::configdirector::rule_id("new-checkout-flow-production-beta-testers")
type = "conditional"
order = 0
target = "value"
value = true
conditions = [
{
id = provider::configdirector::rule_id("new-checkout-flow-production-beta-testers-segment")
kind = "segment"
operator = "in"
segmentId = configdirector_segment.beta_testers.id
}
]
}
]
}
An existing segment is imported by the project's id or slug and the segment's key, for example terraform import configdirector_segment.beta_testers targeting-rules-example/beta-testers. The groups and overrides cannot be read back, so the first apply after an import sends whatever the configuration declares.
Config tags
Declare config assignments by name with tags on configdirector_config. A managed tag's .name reference makes Terraform or OpenTofu wait for that tag's creation or rename:
resource "configdirector_tag" "payments" {
project_id = configdirector_project.example.id
name = "Payments / EU & US"
}
resource "configdirector_config" "checkout" {
project_id = configdirector_project.example.id
key = "checkout-enabled"
role = "flag"
lifetime = "temporary"
type = "boolean"
initial_value = false
tags = [configdirector_tag.payments.name]
}
You can also assign existing literal names, such as tags = ["Payments / EU & US"]. Names are resolved within the config's project using the API's trimming and case-equivalent matching. Spaces, slashes, and punctuation are literal; do not URL-encode them. An unknown name fails with a diagnostic naming the tag and project. Assignments never create tags implicitly. Unknown .name references stay unknown during planning until the tag is available.
| Configuration | Effect |
|---|---|
Omit tags, or use null | Observe names and preserve remote assignments |
tags = [] | Clear every assignment and manage an empty selection |
| A nonempty set of names | Manage that selection and correct assignment drift |
Omission preserves assignments after import and during unrelated updates. Removing tags relinquishes ownership without clearing the selection. Import a config with <project_id_or_slug>/<key>, for example terraform import configdirector_config.checkout targeting-rules-example/checkout-enabled or the same command with tofu. After refresh, omit tags to preserve assignments or declare a set to take ownership.
Assignments are unordered and limited to 20 distinct project tags. Equivalent spellings share one stable ID; state retains configured spelling while the assigned tag IDs are unchanged, so casing and order alone do not cause repeated drift. A shared tag deletion detaches its assignments, and a declared name that no longer exists fails on the next write. Tags organize configs without affecting evaluation.
Name resolution requires tags:read. Tagged creation also requires configs:create and config-settings:update; updates require config-settings:update. Provider updates also read the config back, so include configs:read for that step. Omitted and empty selections need no catalog lookup. The tag resource separately needs tags:create, tags:update, and tags:delete for the corresponding catalog operations, plus tags:read for refresh. Missing scopes produce errors instead of silently skipping assignments.
data.configdirector_config.<name>.tags and each config in data.configdirector_configs.<name>.configs expose current assigned names under configs:read alone. No standalone tag lookup data source is required. The resource and data-source configuration is the same in Terraform and OpenTofu.
Assignment support can deploy once the catalog and assignment APIs are available on every API instance. It does not depend on config table filters or dashboard feature flags.
OpenTofu
The ConfigDirector provider is also available in the OpenTofu registry.