# Introduction
> ConfigDirector is a cloud service to manage remote configuration and feature flags.
ConfigDirector is designed to provide your applications with **safety** and **longevity**. Safety by having enforced types, validations, and integrity alerts. Longevity by allowing you to safely rename obsolete names, tracking the lifecycle of feature flags and configs, and alerting on deprecated values in need of maintenance.
## Get started
| Kind of SDK | Default polling interval | Minimum polling interval |
|---|---|---|
| Client SDKs (JavaScript, React, Vue, Next.js client side, Nuxt client side, React Native, Flutter, Swift, Android, and their OpenFeature providers) | 60 seconds | 30 seconds |
| Server SDKs (Node.js, Next.js server side, Nuxt server side, Python, Java, .NET, Go, and their OpenFeature providers) | 300 seconds (5 minutes) | 60 seconds |
| Limit | Value |
|---|---|
| Schema size | 32 KB |
| JSON value size | 16 KB |
| Nesting depth of a schema | 50 levels |
Items in an
enum
|
1,000 |
| Regular expression patterns per schema | 32 |
| Length of any given regex pattern | 512 characters |
Branches across
anyOf
,
oneOf
, and
allOf
|
100 |
| Operation | Free | Pay as you go |
|---|---|---|
| Schema updates per hour | 20 | No limit |
| JSON value validations per hour | 300 | No limit |
| Metric | What is counted |
|---|---|
| Monthly active users | A distinct user, device, or other context that your client apps identify to ConfigDirector in a calendar month, or a distinct app install or browser that evaluates configs without identifying anyone. Each one counts once a month across all your projects and environments: the same identifier signed in on two devices counts once, and a person who uses your app anonymously and then signs in counts twice. Only client SDKs count: the browser and mobile SDKs, and the browser side of the Next.js and Nuxt SDKs. |
| Service connection hours |
The hours server SDKs spend connected or persistently polling. A server SDK in
polling
mode counts 5 minutes per request, which at the default 5-minute interval matches a
streaming
connection. 750 hours covers one server connected all month, with a buffer for deploys and traffic spikes.
|
| Admin API requests | Calls to the Admin API, including every tool call made through the MCP server and every change applied by the Terraform provider . Dashboard use and SDK evaluations are not Admin API requests. |
| Metric | Free allowance per month |
|---|---|
| Monthly active users | 1,000 |
| Service connection hours | 2,250, about 3 servers connected continuously all month |
| Admin API requests | 10,000 |
| Monthly active users | Per 1,000 users |
|---|---|
| First 1,000 | Free |
| 1,000 to 500,000 | $5.00 |
| 500,000 to 1,000,000 | $3.75 |
| Over 1,000,000 | $2.50 |
| Service connection hours | Per 750 hours |
|---|---|
| First 2,250 | Free |
| 2,250 to 7,500 | $6.00 |
| 7,500 to 22,500 | $5.00 |
| Over 22,500 | $3.50 |
| Admin API requests | Per 10K requests |
|---|---|
| First 10,000 | Free |
| 10,000 to 250,000 | $1.00 |
| 250,000 to 1,000,000 | $0.75 |
| Over 1,000,000 | $0.50 |
| Limit | Value |
|---|---|
| Projects | 5 on Free, unlimited on Pay as you go |
| Configs, across the organization | 100 on Free, unlimited on Pay as you go |
| Members | Unlimited |
| Member invitations | 50 per organization and 6 per email address, in any 24 hours |
| Organization name | 300 characters |
| Limit | Value |
|---|---|
| Environments per project |
Unlimited.
Test
and
Production
are created with the project.
|
| Project name and slug | 255 characters each |
| Environment name | 200 characters |
| Environment slug | 150 characters |
| Client SDK keys per environment | 5 |
| Server SDK keys per environment | 5 |
| Tags per project | Unlimited. A tag name is 1 to 50 characters, unique in the project ignoring case. |
| Limit | Value |
|---|---|
| Config key | 4 to 150 characters: letters, numbers, periods, dashes, and underscores, starting with a letter or number. Unique in the project. |
| Old keys kept after a rename | 2 at a time. See Configs Anatomy . |
| Description | 1,000 characters |
| Variation name | 150 characters |
| String, enum, and URL values | 1,000 characters |
| Integer and float values | 60 digits |
| Timespan values and constraints | Up to 9,007,199,254,740,991, the largest exact integer in JavaScript |
| JSON values | 16 KB |
| JSON Schema | 32 KB, with the schema limits on JSON Schema validation |
| Tags per config | 20 |
| Values across a project | 1 MB |
| Limit | Value |
|---|---|
| Values in one percentage rollout | 20 |
| Segment conditions in one targeting rule | 10 |
| Trait path in a condition | 500 characters |
| Context kind | 1 to 64 lowercase letters, digits, dashes, or underscores |
| Segments per project | 200 |
| Condition groups per segment, and per environment override | 10 |
| Conditions per condition group | 20 |
| Segment name | 150 characters |
| Limit | Value |
|---|---|
| Admin API requests | 10,000 a month in the free allowance, then per request on Pay as you go |
| Request body |
4 MB. A larger body is refused with
413
.
|
| MCP tool calls |
60 per minute per organization. Calls over the rate are refused with
429
until the minute passes.
|
| Schema updates on Free | 20 per hour, see hourly budgets |
| JSON value validations on Free | 300 per hour, see hourly budgets |
| What | Kept for |
|---|---|
| Evaluation activity charts | The Activity tab shows up to the last 30 days. The configs list's weekly evaluation counts cover the last 7 days. |
| Activity data behind lifecycle and alerts | The daily summaries that size quiet windows cover 60 days. Individual evaluation and connection records are archived after 60 days and deleted after 180. |
| Archived configs | Restorable for 30 days, then purged. See Config Lifecycle . |
| Old config keys after a rename | At least 35 days, and until the old key is no longer used. See Dynamic Detection . |
| Alerts | A resolved alert is removed 30 days after it resolves, a dismissed one 30 days after the dismissal, and an alert you have read but not dismissed leaves your inbox after 90 days. Dismissals themselves expire per alert kind, see Alerts . |
| Alert sightings | The detection history behind an alert's grace period is kept for 30 days. |
my-config-key: {value}
); } export default YourComponent; ``` ```vue [YourComponent.vue]my-config-key: {value}
; } export default YourComponent; ``` ```dart [main.dart (Use the client)] import 'config_director_setup.dart'; // Retrieve the current value final value = client.getValue('my-config-key', false); // Subscribe to value updates final subscription = client.watch('my-config-key', false).listen((newValue) { debugPrint('Value updated: $newValue'); }); await subscription.cancel(); // Cancel the subscription to remove the listener client.unwatch('my-config-key'); // Closes every stream watching that key ``` ```swift [ContentView.swift] // Retrieve the current value. The default value decides the type the config // is read as, and is returned until the client is ready. let darkMode = client.value(for: "my-config-key", default: false) // Subscribe to value updates. The stream yields the current value right away // and then every time the evaluated value changes. for await darkMode in client.values(for: "my-config-key", default: false) { print("Value updated: \(darkMode)") } ```my-config-key: {value}
); } export default YourComponent; ``` Retrieving config values in server routes: ```ts [route.ts] import { getConfigClient } from "@configdirector/nextjs-sdk/server"; export async function GET() { const client = getConfigClient(); const value = client.getValue("my-config-key", false); return Response.json({ "my-config-key": value }); } ``` Retrieving config values in components: ```vue [YourComponent.vue]My config value: {myConfigValue}
my-config-key: {String(value)}
| SDK | Package | Segments supported since |
|---|---|---|
| Node.js |
@configdirector/server-sdk
|
1.9.1 |
| Next.js (server side) |
@configdirector/nextjs-sdk
|
1.9.2 |
| Nuxt (server side) |
@configdirector/nuxt-sdk
|
1.9.2 |
| Python |
configdirector-server-sdk
|
1.6.1 |
| Java |
com.configdirector:server-sdk
|
1.8.1 |
| .NET |
ConfigDirector.ServerSdk
|
1.7.1 |
| Go |
github.com/ConfigDirector/go-sdks/configdirector
|
0.1.0 |
| OpenFeature Node.js |
@configdirector/openfeature-server-provider
|
1.9.1 |
| OpenFeature Python |
configdirector-openfeature-server-provider
|
1.4.1 |
| OpenFeature Java |
com.configdirector:openfeature-server-provider
|
1.5.1 |
| OpenFeature .NET |
ConfigDirector.OpenFeature.ServerProvider
|
1.4.1 |
| OpenFeature Go |
github.com/ConfigDirector/go-sdks/configdirector-openfeature
|
0.1.0 |
| Limit | Value |
|---|---|
| Segments per project | 200 |
| Condition groups per segment, and per environment override | 10 |
| Conditions per condition group | 20 |
| Segment conditions per targeting rule | 10 |
| Marker | Meaning |
|---|---|
| Matched | Every condition held, or the context fell into one of the rule's percentage shares. |
| Not matched | At least one condition did not hold, or the context fell outside every share. |
| Not evaluated | An earlier rule already served the value, so this rule was not reached. |
| Error | The rule could not be evaluated. |
code
|
Meaning |
|---|---|
AUTHORIZATION_HEADER_MISSING
|
The request has no
Authorization
header.
|
AUTHORIZATION_HEADER_INVALID
|
The header is not of the form
Bearer
.
|
API_TOKEN_NOT_FOUND
|
No token matches. It may have been revoked, deleted 7 days after it expired, or its organization disabled. |
API_TOKEN_EXPIRED
|
The token's expiration date has passed. The message says when. You get this code for 7 days after the token expires. Create a new token. |
API_TOKEN_OWNER_REMOVED
|
The member who created the token no longer belongs to the organization. Create a new token. |
INSUFFICIENT_PERMISSIONS
|
The token is valid but lacks the permission the endpoint needs. The endpoint table below names each one. |
| Resource | Permissions |
|---|---|
| Projects |
projects:read
,
projects:create
,
projects:update
,
projects:delete
|
| Environments |
environments:read
,
environments:create
,
environments:update
,
environments:delete
|
| Configs |
configs:read
,
configs:create
,
config-settings:update
,
config-targeting-rules:update
,
configs:archive
|
| Segments |
segments:read
,
segments:create
,
segments:update
,
segments:delete
|
| Tags |
tags:read
,
tags:create
,
tags:update
,
tags:delete
|
| Code references |
code-references:read
,
code-references:update
|
| Contexts |
contexts:read
, to evaluate a config for a saved context
|
| Webhooks |
webhooks:manage
, for every webhook endpoint. Only owners and admins can give it to a token.
|
| Status | When |
|---|---|
200
|
The request succeeded and the body holds the resource. |
204
|
The request succeeded and there is nothing to return: updating a project or targeting rules, archiving a config, and deletions. |
400
|
The body failed validation. The response lists each problem, with the field it concerns when there is one. A config key that is already in use in the project is reported this way too. A repository scan over one of its bounds is reported this way, naming the bound; a scan that would give a project its 51st scanned repository is refused with
{ "error": "...", "code": "REPOSITORY_LIMIT_REACHED" }
instead. A webhook URL that is not
https://
or whose host is private or cannot be found, an organization's 11th webhook, and a test or resend on a disabled webhook are reported this way too. Deleting a project or environment whose deletion protection is on, or a project with a protected environment, is reported this way too, naming where to turn it off.
|
403
|
Not authenticated, or the token lacks the permission. See Authentication . |
404
|
No resource with that id or key exists in the project or organization. The body says which,
{ "error": "...", "code": "CONFIG_NOT_FOUND" }
, with
code
one of
PROJECT_NOT_FOUND
,
ENVIRONMENT_NOT_FOUND
,
CONFIG_NOT_FOUND
,
SEGMENT_NOT_FOUND
,
TAG_NOT_FOUND
,
SCANNED_REPOSITORY_NOT_FOUND
,
CONTEXT_NOT_FOUND
,
WEBHOOK_NOT_FOUND
,
WEBHOOK_DELIVERY_NOT_FOUND
,
API_TOKEN_NOT_FOUND
or
EXPERIMENT_RUN_NOT_FOUND
. A project id that no project of the organization has gets
PROJECT_NOT_FOUND
on every endpoint under
/projects/{projectId}
. An id in the path that is not a UUID gets an empty body.
|
409
|
Deleting a segment that the targeting rules of a config still use. The body's
usages
lists each config and the environments whose rules use it.
|
413
|
The request body is larger than 4 MB, or larger than 32 MB when uploading a repository scan. |
429
|
Service is suspended, because a Free organization has stayed over its free allowance past the billing grace period or a Pay as you go organization has reached its spending limit. The body is
{ "error": "Service suspended", "code": "SERVICE_SUSPENDED" }
with a
Retry-After
header. A Free organization that has used up an hourly
JSON Schema budget
gets
429
too, with a message that says when the budget resets.
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/api-token
|
Describe the API token that sends the request: its name, its organization's id and name, its permissions, and when it expires. Use it to tell which organization a token belongs to and what it can do. | None, only a valid API token |
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects
|
List the organization's projects, without their environments. Each carries
storeCodeSnippets
, whether the project stores code snippets, and
deletionProtection
, whether the project is protected from deletion.
|
projects:read
|
POST
|
/projects
|
Create a project from a
name
and a
slug
. Returns it with its environments,
Test
and
Production
.
|
projects:create
|
GET
|
/projects/{projectId}
|
Get a project with its environments. |
projects:read
|
PUT
|
/projects/{projectId}
|
Rename a project or change its slug. The project's Code snippets setting,
storeCodeSnippets
, and its Deletion protection setting,
deletionProtection
, are read-only here and change in the dashboard.
|
projects:update
|
DELETE
|
/projects/{projectId}
|
Delete a project with everything in it. |
projects:delete
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects/{projectId}/environments
|
List the project's environments. Each carries
deletionProtection
, whether the environment is protected from deletion.
|
environments:read
|
POST
|
/projects/{projectId}/environments
|
Create an environment from a
name
, a
slug
, a
color
, and whether it is
live
.
|
environments:create
|
GET
|
/projects/{projectId}/environments/{environmentId}
|
Get an environment. |
environments:read
|
PUT
|
/projects/{projectId}/environments/{environmentId}
|
Update an environment's name, slug, color, or live flag. The environment's Deletion protection setting,
deletionProtection
, is read-only here and changes in the dashboard.
|
environments:update
|
DELETE
|
/projects/{projectId}/environments/{environmentId}
|
Delete an environment and everything in it. |
environments:delete
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects/{projectId}/configs
|
List the project's configs in key order, without targeting rules.
search
lists the configs whose key or description contains the text, ignoring case.
role
,
type
,
status
(the lifecycle state, such as
settled
or
stale
) and
lifetime
take one value each. Repeat
tagIds
to list the configs that have any of those tags, or send
untagged=true
for the configs without tags. A config is listed only when it matches every filter sent.
|
configs:read
|
POST
|
/projects/{projectId}/configs
|
Create a config from its
key
,
role
,
type
, and
defaultValue
, which becomes the default targeting rule value in every environment.
lifetime
is required for the
config
role and optional for the others, whose role decides it:
flag
and
experiment
are always
temporary
,
kill-switch
always
permanent
, and a value sent for those must match. Optional:
description
,
typeOptions
for the type's constraints,
client
and
server
availability,
variations
, and
tagIds
.
|
configs:create
|
GET
|
/projects/{projectId}/configs/{configKey}
|
Get a config with its targeting rules in every environment. |
configs:read
|
PATCH
|
/projects/{projectId}/configs/{configKey}
|
Update the config's settings:
key
,
description
,
role
,
lifetime
,
typeOptions
,
variations
,
availability
, or
tagIds
. Only the fields sent change.
role
can only be updated from
flag
to
kill-switch
and back; an update to
kill-switch
makes the config permanent and resolves its open lifecycle and in-code default value mismatch alerts, an update to
flag
makes it temporary. A
lifetime
sent for a
flag
,
kill-switch
or
experiment
must match the role after the update. The
type
is never updated.
|
config-settings:update
|
PUT
|
/projects/{projectId}/configs/{configKey}/targets
|
Replace the targeting rules of one environment. See Updating targeting rules . |
config-targeting-rules:update
|
GET
|
/projects/{projectId}/configs/{configKey}/activity
|
The time of the most recent evaluation per environment, SDK key kind, SDK name, and SDK version. |
configs:read
|
POST
|
/projects/{projectId}/configs/{configKey}/evaluate
|
Evaluate the config for a context in one environment and explain the result: the value served, the rule that served it, and what happened to each rule. See Evaluating a config . |
configs:read
|
POST
|
/projects/{projectId}/configs/{configKey}/copy
|
Copy the config into a new one under the
key
the body names, in this project or in the project
projectId
names, with its definition, tags and every environment's targeting rules.
dryRun: true
returns the plan without creating anything. See
Copying a config
.
|
configs:create
|
GET
|
/projects/{projectId}/configs/{configKey}/environments/{environmentId}/runs
|
List an experiment's runs in one environment, newest first. See Experiment runs, shipping and stopping . |
configs:read
|
GET
|
/projects/{projectId}/configs/{configKey}/runs/{runId}
|
Get one run of the config. |
configs:read
|
POST
|
/projects/{projectId}/configs/{configKey}/environments/{environmentId}/ship
|
Ship a variation in one environment: serve it to everyone and end the run. The body names the
variationId
. See
Experiment runs, shipping and stopping
.
|
config-targeting-rules:update
|
POST
|
/projects/{projectId}/configs/{configKey}/environments/{environmentId}/stop
|
Stop the run in one environment: remove its percentage rollouts and keep the default targeting rule. |
config-targeting-rules:update
|
DELETE
|
/projects/{projectId}/configs/{configKey}
|
Archive the config. It can be restored from the dashboard for 30 days. |
configs:archive
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/targeting-rules-reference
|
The format
PUT /projects/{projectId}/configs/{configKey}/targets
accepts: the JSON Schema of the request body, the condition kinds, the operators for each target type, the attributes a condition can test, the operators of context kind and segment conditions, and notes on how rules are evaluated. It is the same document the MCP server's
get_targeting_rules_reference
tool returns.
|
None, only a valid API token |
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects/{projectId}/segments
|
List the project's segments, each with the configs and environments whose rules use it. |
segments:read
|
POST
|
/projects/{projectId}/segments
|
Create a segment from a
key
, a
name
, its condition
groups
, and optional environment
overrides
, a map from environment id to that environment's own groups.
|
segments:create
|
GET
|
/projects/{projectId}/segments/{segmentKey}
|
Get a segment. |
segments:read
|
PUT
|
/projects/{projectId}/segments/{segmentKey}
|
Replace the segment's key, name, and groups. When
overrides
is sent, the environment overrides become exactly that map, so
{}
removes them all; when it is left out, they stay.
|
segments:update
|
DELETE
|
/projects/{projectId}/segments/{segmentKey}
|
Delete the segment and its overrides. Refused with
409
while any config's rules use it.
|
segments:delete
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects/{projectId}/tags
|
List the project's tags by name. |
tags:read
|
POST
|
/projects/{projectId}/tags
|
Create a tag. Names are trimmed, 1 to 50 characters, and unique in the project ignoring case. |
tags:create
|
GET
|
/projects/{projectId}/tags/by-name
|
Find a tag by
name
, ignoring surrounding whitespace and case.
|
tags:read
|
GET
|
/projects/{projectId}/tags/{tagId}
|
Get a tag. |
tags:read
|
PUT
|
/projects/{projectId}/tags/{tagId}
|
Rename a tag. Its id, and every config assignment, stay the same. |
tags:update
|
DELETE
|
/projects/{projectId}/tags/{tagId}
|
Delete a tag. Configs that had it lose the assignment. |
tags:delete
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/projects/{projectId}/repositories
|
List the project's scanned repositories by name, each with its latest scan's
remoteUrl
,
commit
,
scannedAt
and
filesScanned
, the
referenceCount
of direct and indirect references, the
dynamicReferenceCount
the scan could not resolve, and
snippetsStored
, whether its latest upload's snippets were kept.
|
code-references:read
|
PUT
|
/projects/{projectId}/repositories/{repositoryName}
|
Upload a scan:
remoteUrl
,
commit
,
filesScanned
, and the
references
and
dynamicReferences
exactly as
configdirector scan --json
prints them. Replaces every reference the repository uploaded before; the first upload creates the repository. A project holds at most 50 scanned repositories, and a scan uploads at most 10,000 references, dynamic references included. The body may be up to 32 MB.
|
code-references:update
|
DELETE
|
/projects/{projectId}/repositories/{repositoryName}
|
Remove a scanned repository and its references, so a renamed or retired repository no longer keeps configs in code. |
code-references:update
|
| Method | Path | What it does | Permission |
|---|---|---|---|
GET
|
/webhooks
|
List the organization's webhooks in name order, without their secrets. Each carries
lastDelivery
, the newest delivery's
status
,
attempts
,
nextAttemptAt
and
createdAt
, or
null
before the first delivery.
|
webhooks:manage
|
POST
|
/webhooks
|
Create a webhook from a
name
and a
url
. Optional: up to 5 custom
headers
as
{ name, value }
,
enabled
(
true
when left out), the
projectIds
,
environmentIds
and
tagIds
filters (empty matches everything),
eventTypes
(every change type when left out), and
alertKinds
(none when left out). Returns the webhook with its
secret
.
|
webhooks:manage
|
GET
|
/webhooks/{webhookId}
|
Get a webhook with its
secret
. While a rotated secret still signs requests,
previousSecretExpiresAt
says until when.
|
webhooks:manage
|
PUT
|
/webhooks/{webhookId}
|
Replace the webhook's name, URL, custom headers, filters, subscriptions, and whether it is enabled. A header sent without a
value
keeps its saved value, and a header left out is removed. Leaving out
enabled
enables the webhook. The secret never changes here.
|
webhooks:manage
|
DELETE
|
/webhooks/{webhookId}
|
Delete the webhook and its deliveries. |
webhooks:manage
|
POST
|
/webhooks/{webhookId}/rotate-secret
|
Give the webhook a new
secret
. The previous one keeps signing every request too for 24 hours.
|
webhooks:manage
|
POST
|
/webhooks/{webhookId}/test
|
Send a
webhook.test
webhook event. Returns its delivery, pending its first attempt.
|
webhooks:manage
|
GET
|
/webhooks/{webhookId}/deliveries
|
List the webhook's deliveries from the last 30 days, newest first, each with its attempts, the latest response and the webhook event sent. To list only the deliveries in one status, send
status
as
pending
,
succeeded
,
failed
or
abandoned
.
limit
is at most 50, which is also the default; when there are more, send
nextCursor
as
before
for the next page.
|
webhooks:manage
|
POST
|
/webhooks/{webhookId}/deliveries/{deliveryId}/resend
|
Send the delivery's webhook event again under the same
webhook-id
. Returns the delivery, pending its next attempt.
|
webhooks:manage
|
| Skill | What it does | API token permissions |
|---|---|---|
configdirector-setup
|
Adds ConfigDirector to your project: picks the SDK for your framework, installs it, reads the SDK key from an environment variable, creates a first feature flag once you confirm it, or reads the flag you name, and evaluates the flag in your code. |
Projects: Read
,
Configs: Read
,
Configs: Create
, for the first flag
|
configdirector-connect
|
Sets up your agent's access to your ConfigDirector account, through the MCP server or the CLI, for each organization you work for, and checks it. |
Projects: Read
, plus the permissions you choose for the agent
|
configdirector-flag-a-change
|
Wraps a code change in a new temporary feature flag: proposes a key, creates a boolean flag that is off in every environment once you confirm it, and reads it in your code so the change runs where the flag is on and your app behaves as before where it is off, with a test for each branch. |
Projects: Read
,
Configs: Read
,
Configs: Create
|
configdirector-use-configs-in-code
|
Gives your agent the rules for code that reads a config: what the in-code default value is for, the type to read each config as, which SDKs receive it, the evaluation context, keys the CLI can check, and one client per app. Applies when your agent writes or reviews such code. When your agent can reach your account, checks that your project has a config before writing a read, and offers to create one it lacks. |
None of its own; with your agent's access,
Projects: Read
and
Configs: Read
to check a config
|
configdirector-test-with-flags
|
Gives your agent the rules for testing code that reads a config: the SDK's test client or the OpenFeature in-memory provider instead of a mock, no real SDK key, a test for each branch of a flag, and test values of the config's type. Applies when your agent writes tests around flagged code. | None of its own |
configdirector-validate-in-ci
|
Adds
configdirector validate
to your repository's CI, so the build fails when the code reads a config key that does not exist, was renamed, or has the wrong type. On GitHub, it adds the
ConfigDirector Code Scan action
, which can also upload where each config is read on pushes to your default branch, so each config's
Code references
tab shows the code that reads it.
|
Projects: Read
,
Configs: Read
, plus
Code references: Update
for the upload, for a token used only by CI
|
configdirector-clean-up-flag
|
Removes a settled temporary feature flag from your code, keeping the branch it serves: reads the flag's
lifecycle state
, its recent evaluations and every reference
configdirector scan
finds, proposes the branch to keep, and shows the exact change before editing. Stops with the facts when the flag is still in use. Archives the config only once you confirm the removal is deployed everywhere that read the flag.
|
Projects: Read
,
Environments: Read
,
Configs: Read
,
Configs: Archive
|
configdirector-migrate-from-launchdarkly
|
Moves your flags from LaunchDarkly, following the
migration guide
. Recreates a LaunchDarkly project's segments and flags in your project, with the targeting rules of each environment, from flag data you export in your own terminal, so your agent never handles a LaunchDarkly token: proposes which flags to move and which to hardcode, shows each batch of configs next to LaunchDarkly's settings and rules before creating it, and checks the rules with an evaluation. Then switches one application's SDK calls over, runs
configdirector validate
and your checks, and removes the LaunchDarkly package once no read remains. Skips every key your project already has, and changes nothing in LaunchDarkly.
|
Projects: Read
,
Environments: Read
,
Configs: Read
,
Configs: Create
,
Configs: Update targeting rules
,
Segments: Read
,
Segments: Create
, plus
Tags: Read
for flags with tags
|
| Skill | What it does | API token permissions |
|---|---|---|
configdirector-create-config
|
Creates a config of any role and type from your description, such as a kill switch, a timespan with a range, an enum, or an experiment with variations, with the SDKs that receive it and its tags. Marks the tags your project does not have yet as new, shows every setting and the default targeting rule value every environment starts with, asks for the ones it cannot work out from your description, and creates the config, with any new tags, once you confirm. Asks for the lifetime only for a general config, since a feature flag, kill switch or experiment always has the same one. Also updates a feature flag's role to kill switch, which makes it permanent, or a kill switch's to feature flag, after showing what the update does. |
Projects: Read
,
Configs: Read
,
Configs: Create
, plus
Tags: Read
to find the tags your project already has,
Tags: Create
to make new ones and
Configs: Update settings
to update a role
|
configdirector-roll-out
|
Changes a config's targeting rules in one environment from your description: turns a flag on or off, rolls a change out to a percentage, targets specific users, contexts with certain attributes, or a segment, sets an experiment split, or changes the value it serves. Shows the environment's current rules next to the resulting rules and changes them once you confirm, and in a live environment asks for an explicit yes. On request, shows what a context you describe now gets. |
Projects: Read
,
Environments: Read
,
Configs: Read
,
Configs: Update targeting rules
, plus
Segments: Read
for segments and
Contexts: Read
to evaluate a saved context
|
configdirector-segments
|
Creates a segment or changes one from your description: who is in it, as condition groups, its name or key, and an environment override added, changed or removed. Shows the current and resulting definition side by side with the configs that use the segment in the environments the change reaches, and writes it once you confirm; when one of those environments is live and a config uses the segment there, asks for an explicit yes. Never deletes a segment: it shows what uses it and gives you the command or the dashboard page to delete it yourself. |
Projects: Read
,
Environments: Read
,
Segments: Read
, plus
Segments: Create
to create a segment and
Segments: Update
to change one
|
| System | Saved in |
|---|---|
| macOS |
~/Library/Application Support/configdirector/sign-ins.json
|
| Linux |
~/.config/configdirector/sign-ins.json
|
| Windows |
%APPDATA%\configdirector\sign-ins.json
|
| Field | Meaning |
|---|---|
project
|
The project's slug.
--project
and
CONFIGDIRECTOR_PROJECT
take precedence over it.
|
organization
|
The id of the project's organization. A command in the directory uses your sign-in for it, and refuses a token of another organization, such as a
CONFIGDIRECTOR_TOKEN
set for an MCP server, when that organization has a project with the same slug.
--organization
and
CONFIGDIRECTOR_ORGANIZATION
take precedence over it.
|
include
|
Globs of the files to scan, relative to
configdirector.json
.
init
writes
["**"]
, every file.
|
exclude
|
Globs of the files to skip, on top of the files the scan always skips . |
ignoreKeys
|
Keys that
validate
never reports, such as the key of a config another project serves.
|
| Option | Environment variable | Meaning |
|---|---|---|
--token
|
CONFIGDIRECTOR_TOKEN
|
The API token. Without either, the sign-in saved by
login
for the organization named below, or your only sign-in.
|
--organization
|
CONFIGDIRECTOR_ORGANIZATION
|
The organization whose sign-in to use, by the name
login
saved or by its id. Without either, the
organization
in
configdirector.json
. Giving one together with
--token
or
CONFIGDIRECTOR_TOKEN
is a mistake, and the command exits with 2.
|
--project
|
CONFIGDIRECTOR_PROJECT
|
The project's slug. Without either, every command that reads a project uses the
project
in
configdirector.json
.
projects list
and
targeting-rules reference
ignore all three.
|
--base-url
|
CONFIGDIRECTOR_BASE_URL
|
The Admin API host. Defaults to
https://api.configdirector.com
.
|
--json
|
Print JSON instead of text. See Output . |
| Problem | What it means for your app | What to do |
|---|---|---|
| Unknown keys | No config in the project has this key, as its current key or an old one, so the SDK returns the in-code default value every time. The key of an archived config is unknown too. |
Correct the key, or create the config. If another project serves the key, add it to
ignoreKeys
.
|
| Deprecated keys | The config was renamed, and the code still reads an old key. The old key works until ConfigDirector removes it once it is no longer used, as Key explains. | Replace it with the current key, which the output names. |
| Type mismatches |
The in-code default value, or a getter whose name sets the type such as
getBoolean
, reads the config as a type the SDKs do not serve it as, so the SDK can return the in-code default value instead of the config's value.
|
Read the config as the type the output names. |
| Availability mismatches | A client SDK reads a server-only config, or a server SDK reads a client-only one. That SDK never receives the config, so it returns the in-code default value every time. | Change the config's SDK availability , or read the config where it is served. |
| Enum values not allowed | The in-code default value is not one of the enum's allowed values. | Use an allowed value as the in-code default value, or add the value to the enum. |
| Code | Meaning |
|---|---|
0
|
The command succeeded. For
validate
, it found no problem.
|
1
|
validate
found at least one problem, or
configs create
found a config that already has the key.
|
2
|
The command could not run: a mistake in the command, no token or a rejected one, a token of another organization than the repository's, a missing permission, a suspended service, an unreachable API, or something the command names that does not exist, such as a config key, an environment, a saved context, a segment key, a tag or a scanned repository.
segments delete
also exits with 2 when the targeting rules of a config use the segment. The message says which.
|
| Input | Default | What it does |
|---|---|---|
token
|
Required. The API token, from a secret. | |
version
|
latest
|
The version of
@configdirector/cli
to run, or an npm dist-tag. A version number from the
changelog
,
0.9.0-beta.1
or later, upgrades on your own schedule.
|
working-directory
|
.
|
The directory that holds
configdirector.json
. The scan reads the files under it.
|
upload
|
auto
|
When the scan is uploaded:
auto
on pushes to the default branch only,
true
on every run,
false
never.
|
context-lines
|
2
|
How many lines before and after each reference its snippet holds, from 0 to 5. |
snippets
|
true
|
false
uploads no code, as
--no-snippets
does.
|
| Outcome | What it means |
|---|---|
matched
|
The context meets every condition of the rule, and for a percentage rollout, its bucket falls in a share. The value comes from this rule. |
not matched
|
The rule does not apply to the context. The output names the first condition that failed and the context's value for it, such as
plan is one of pro, team, but it is "free"
, or the bucket the context fell in outside the rule's shares.
|
not evaluated
|
An earlier rule served the value, so this rule was not checked. |
errored
|
The rule could not be evaluated, so it was skipped, as an SDK skips it. |
| Command | What it shows | Permission |
|---|---|---|
configdirector projects list
|
Your organization's projects, with their slugs and names |
Projects: Read
|
configdirector environments list
|
The project's environments, with their slugs and names, marking the live ones |
Environments: Read
|
configdirector configs list
|
The project's configs, with their type, role, lifetime and lifecycle state |
Configs: Read
|
configdirector configs get
|
A config's settings, then its targeting rules in every environment |
Configs: Read
|
configdirector configs activity
|
When SDKs last evaluated the config, per environment, SDK key kind, SDK name and SDK version |
Configs: Read
|
configdirector segments list
|
The project's segments, with how many configs use each |
Segments: Read
|
configdirector segments get
|
A segment's condition groups and its environment overrides |
Segments: Read
|
configdirector api-token get
|
The token a command here would use: its organization, name, permissions and expiration, and whether it came from
--token
,
CONFIGDIRECTOR_TOKEN
or a sign-in. Never the token itself
|
Any valid token |
| Option | Meaning |
|---|---|
--key
|
Required. The config's key . |
--type
|
Required.
boolean
,
string
,
integer
,
float
,
timespan
,
enum
,
url
or
json
.
|
--role
|
Required.
config
,
flag
,
kill-switch
or
experiment
. Flags and kill switches are booleans, as
Roles
describes.
|
--lifetime
|
Required for the
config
role.
temporary
or
permanent
. The other roles decide their own lifetime, as described below.
|
--default-value
|
Required. The default targeting rule value every environment starts with. It is not the in-code default value your application passes to the SDK. |
--description
|
A description shown with the config in the dashboard. |
--client-only
,
--server-only
|
Serve the config to one kind of SDK only. Without either, client and server SDKs both receive it. |
--tag
|
A tag the project already has, by its name. Repeat it for each tag. A name no tag has stops the command with exit code 2. |
--new-tag
|
A tag to create in the project's tag catalog and assign, by its name. Repeat it for each tag. A name a tag already has stops the command with exit code 2. |
--variation
|
A variation of an experiment. Repeat it for each variation. |
| Type | Options |
|---|---|
integer
,
float
|
--min
and
--max
set bounds a value may equal;
--exclusive-min
and
--exclusive-max
set bounds a value must stay inside.
|
timespan
|
--unit
(
milliseconds
,
seconds
or
minutes
),
--min
and
--max
, which a timespan needs, and
--allow-fractions
to accept values such as
1.5
. A value may equal either bound.
|
enum
|
--allowed-value
for each value the config can take, and
--enum-value-type number
when the values are numbers. They are strings otherwise.
|
url
|
--https-only
to accept only HTTPS URLs. Without it, any HTTP or HTTPS URL is accepted.
|
json
|
--json-schema
, a file holding the
JSON Schema
every value must match.
|
| Option | Meaning |
|---|---|
|
Required. The key of the config to copy, in the linked project. An old key of the config works too. |
--key
|
Required. The copy's key , which no config in the destination project may have. |
--to
|
The project to copy the config into, another project of the organization. Without it, the copy is created in the config's own project. |
--environment
|
The environment of the config's project that an environment of the destination project copies its targeting rules from. Repeat it for each one. |
--dry-run
|
Print the plan without creating anything. |
kind
|
Also has |
|---|---|
unknown-key
|
|
deprecated-key
|
currentKey
|
type-mismatch
|
configType
,
servedAs
, and
default
,
getterType
or both
|
availability-mismatch
|
sdk
,
sdkType
,
configAvailableTo
|
enum-value-not-allowed
|
default
,
allowedValues
|
| Tools | What they do |
|---|---|
list_projects
,
get_project
,
create_project
,
update_project
|
Retrieve projects general information. Create and update projects in your organization. |
list_environments
,
get_environment
,
create_environment
,
update_environment
|
Retrieve environments within a project. Create new environments, and update environments. |
list_configs
,
get_config
,
get_config_activity
|
Retrieve Configs, their targeting rules per environment, and their most recent evaluations.
list_configs
takes the same search and filters as the configs list in the dashboard.
|
evaluate_config
|
Evaluate a config for a context in an environment and explain the result: the value served, the rule that served it, and why each rule matched or not. Takes an inline context, a saved context (which also needs
Contexts: Read
), or no context at all for an anonymous visitor. Creates no SDK activity.
|
create_config
,
update_config_settings
|
Create configs, feature flags, kill switches, or experiments; the role decides the lifetime of every role but config, so only a config needs one. Update their settings, for example, the allowed values in an enum, or update a feature flag to a kill switch and back. |
copy_config
|
Copy a config into a new config, in the same project or another project of your organization, with its tags and every environment's targeting rules. Across projects, environments are matched by slug, tags by name, and segments by key: a rule whose segment the destination project doesn't have is left out, and a missing tag is created only with
Tags: Create
. Each copy reports what it carried over: for each environment, where its rules came from and which rules were left out, and which tags were matched, created, or skipped. A dry run gives that report without creating anything.
|
archive_config
|
Archive a config. The dashboard can restore it for 30 days. |
update_targeting_rules
|
Update the targeting rules of a config in a given environment. |
get_targeting_rules_reference
|
Retrieves the targeting rules format, operators, and target types. This is used by the assistant to write valid targeting rules |
list_segments
,
get_segment
|
Retrieve the segments of a project, with their condition groups, environment overrides, and the configs that use them. |
create_segment
,
update_segment
,
delete_segment
|
Create, update, and delete segments. A segment cannot be deleted while the targeting rules of a config use it. |
list_tags
,
get_tag
,
find_tag_by_name
|
Browse the shared project tag catalog and resolve a stable ID by name. Requires
tags:read
.
|
create_tag
|
Create a shared project tag with a trimmed, case-insensitively unique name of 1–50 characters. Requires
tags:create
.
|
| 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 |
| Field | What it holds |
|---|---|
id
|
The webhook event's id. It is the same on every webhook that receives the webhook event and on every resend, and it is also sent as the
webhook-id
header. Use it to drop duplicates.
|
type
|
What happened, such as
targeting_rules.updated
. See
Webhook event types
.
|
createdAt
|
When the change was made, or when the alert was raised or resolved. |
organization
|
The organization's
id
and
name
.
|
project
|
The project's
id
,
slug
, and
name
. Every change has one.
|
environment
|
The environment's
id
,
slug
,
name
, and whether it is
live
. Present on targeting rules changes, environment changes, and a segment change to one environment's override.
|
config
|
The config's
id
and
key
. Present on config and targeting rules changes.
|
actor
|
Who made the change.
member
holds the member's
id
,
name
, and
email
;
name
and
email
are
null
if the member's account has been deleted.
sourceClient
is where the change came from:
dashboard
,
api
,
terraform
,
opentofu
,
mcp
, or
cli
.
apiToken
holds the token's
id
and
name
when the change was made with an API token. Alert and test webhook events have no actor.
|
alertKind
|
The alert's kind, on alert webhook events only. |
data.object
|
The entity after the change, as the Admin API returns it. On a deletion it is the entity as it was just before, and some fields, such as
createdAt
,
updatedAt
, and a segment's
overrides
, can be missing.
|
data.previousAttributes
|
On
*.updated
webhook events only: each property that changed, with its value before the change.
|
| Filter | Lets a webhook event through when | Also lets through |
|---|---|---|
| Projects | it belongs to one of the projects | nothing else: alert webhook events belong to no project, so a webhook filtered to projects receives no alert webhook events |
| Environments | it belongs to one of the environments | every webhook event that belongs to no environment: config settings, segments (except a change to one environment's override), projects, and alerts |
| Tags | it is about a config that has one of the tags | every webhook event that is not about a config: segments, environments, projects, and alerts |
| Header | Value |
|---|---|
webhook-id
|
The webhook event's
id
.
|
webhook-timestamp
|
When this attempt was sent, in seconds since the Unix epoch. Every attempt, including retries and resends, gets a fresh one. |
webhook-signature
|
v1,
followed by the base64 HMAC-SHA256 of
{webhook-id}.{webhook-timestamp}.{body}
. The HMAC key is the signing secret's text after
whsec_
, decoded from base64. While a rotated secret still signs, the header holds two signatures separated by a space.
|
content-type
|
application/json
|
user-agent
|
ConfigDirector-Webhooks/1
|
| Language | Install |
|---|---|
| Node.js and TypeScript |
npm install standardwebhooks
|
| Python |
pip install standardwebhooks
|
| Go |
go get github.com/standard-webhooks/standard-webhooks/libraries/go
|
| Java and Kotlin |
implementation("com.standardwebhooks:standardwebhooks:1.2.0")
|
| C# |
dotnet add package StandardWebhooks.StandardWebhooks
|
| Ruby |
bundle add standardwebhooks
|
| PHP |
composer require standard-webhooks/standard-webhooks
|
| Rust |
cargo add standardwebhooks
|
| Type | Sent when |
data.object
|
data.previousAttributes
can hold
|
|---|---|---|---|
config.created
|
A config is created. Its first targeting rules send nothing of their own. | The config as the Admin API lists it, without targeting rules | |
config.updated
|
A config's settings change, or it gets a new key | Same |
description
,
role
,
lifetime
,
type
,
typeOptions
,
variations
,
client
,
server
,
tags
,
key
|
config.archived
|
A config is archived | The config as it was archived | |
config.restored
|
An archived config is restored | The config as restored | |
targeting_rules.updated
|
The targeting rules of one environment change |
That environment's targeting rules:
id
,
environment
,
rules
,
defaultValue
,
defaultValueId
, and
defaultVariationId
on an experiment
|
rules
,
defaultValue
,
defaultValueId
,
defaultVariationId
|
segment.created
,
segment.updated
,
segment.deleted
|
A segment is created, changed, or deleted |
The segment as the Admin API returns it, without
usages
|
key
,
name
,
kind
,
groups
, or
overrides
when one environment's override changed
|
environment.created
,
environment.updated
,
environment.deleted
|
An environment is created, changed, or deleted | The environment as the Admin API returns it |
name
,
slug
,
color
,
live
,
deletionProtection
|
project.created
,
project.updated
,
project.deleted
|
A project is created, changed, or deleted | The project as the Admin API returns it, without its environments |
name
,
slug
,
storeCodeSnippets
,
deletionProtection
|
alert.created
,
alert.resolved
|
An alert of a kind the webhook subscribes to is raised or resolved |
The alert:
id
,
kind
,
priority
,
facts
,
detectedAt
,
createdAt
,
resolvedAt
, and
url
, its page in the dashboard
|
|
webhook.test
|
Someone sends a test webhook event |
None:
data.sample
holds a sample
targeting_rules.updated
webhook event
|
| Limit | Value |
|---|---|
| Webhooks per organization | 10 |
| Custom headers per webhook | 5, each value up to 1,024 characters |
| Response time | 10 seconds |
| Delivery history | 30 days, after which deliveries are deleted and can no longer be resent |
| Webhook event size | 256 KB |
| Firebase Remote Config | ConfigDirector |
|---|---|
| Firebase project, one per stage | One project with an environment per stage. Each environment has its own SDK keys and its own targeting rules for every config. |
| Parameter |
Config
. A boolean parameter that gates a feature is a config with the
Feature flag
role if it is temporary, or
Kill switch
if it stays; everything else is a
Config
.
|
| Value type: string, boolean, number, JSON |
Config
type
:
String
,
Boolean
,
Integer
or
Float
,
JSON
. ConfigDirector also has
Enum
,
URL
, and
Timespan
, which validate the value as that type. A string parameter with a fixed set of values is an
Enum
; a string holding a URL is a
URL
; a number of milliseconds or seconds is a
Timespan
.
|
| Default value | The default targeting rule value : the value of the last rule in each environment, served when no other rule matches. |
| Conditional value | A conditional rule above the default targeting rule, with the condition and the value it serves. Rules are checked in order; the first that matches serves its value. |
| Condition, named and shared across parameters | Conditions are written on each rule. A condition you reuse across many configs becomes a segment , defined once per project and used by a rule as "the context is in the segment". |
| Parameter group | Tags |
| Description | Description |
| Parameter key | Config key . Firebase keys made of letters, digits, and underscores are valid ConfigDirector keys, so keep them: the code change is then only the SDK call. A key can be renamed safely later, even in production. |
In-app default values, from XML, plist, JSON, or
defaultConfig
|
The in-code default value , passed with every read. It is returned when the client has no values for the context yet, and when the config is missing or has the wrong type. |
| Template versions, diff, and rollback | The config's audit log, with who changed what, from where, and the before and after values. There is no one-click rollback: restore a value by setting it again. |
| Template JSON, exported and published through the CLI or REST | The Terraform provider , the MCP server , and the Admin API. Configs and targeting rules are managed as code with the same validations as the dashboard. |
| Value limits: 3,000 parameters, 1,000,000 characters | 100 configs on Free, unlimited on Pay as you go. 16 KB per value and 1 MB per project. See Pricing and billing . |
| Remote Config condition | ConfigDirector |
|---|---|
| App version, build number |
An
appVersion
condition, compared as a semantic version. The mobile SDKs read the app version from the platform when you do not set it; the browser SDK takes it from the
metadata
option.
|
| App, platform |
An
appName
condition. Give each platform build its own name through the
metadata
option, such as
my-app-ios
and
my-app-android
, or use one config per platform.
|
| Country or region, language, device category, OS |
A condition on a trait your app sets, such as
/country
,
/language
, or
/platform
. ConfigDirector does not collect these on its own; put the ones your rules use into the context's
traits
.
|
| User property, Analytics audience, custom signal | A condition on a trait, or a segment with the audience's definition. Traits can hold strings, numbers, booleans, arrays, and nested objects, and a condition reads a trait as text, a number, a semantic version, a datetime, an array, or a boolean. |
| User in random percentile | A percentage rollout . Each context is assigned by its context kind and identifier, so a user keeps the same value on every device they sign in on, and across app restarts. |
| First open time |
A trait your app sets, such as
/firstOpenedAt
, compared as a datetime.
|
| Date and time | Not available. There are no scheduled changes; change the rule when the time comes, or apply the change from a scheduled job through the Admin API, the Terraform provider, or the MCP server. |
| Imported segment |
A
segment
with the same definition, or a condition group with
identifier is one of
the listed identifiers.
|
| Firebase | ConfigDirector |
|---|---|
| A/B Testing experiment on a parameter |
A config with the
Experiment
role. It defines named
variations
and serves them to segments or by percentage. ConfigDirector does not measure the outcome: send the variation to your analytics, using the
valueId
every evaluation carries if you prefer not to send the value itself.
|
| Rollout with Crashlytics and Analytics metrics | A percentage rollout that you widen as you watch your own monitoring. Alerts tell you about problems with the config itself, such as a type mismatch or the in-code default value being served too often. |
| Firebase Remote Config | ConfigDirector |
|---|---|
| Fetch, then activate |
initialize
once, when the app starts. There is no activate step: values are ready to read as soon as
initialize
completes.
|
| Minimum fetch interval, 12 hours by default | None. The SDK keeps a streaming connection open and receives every change within about a second of it being saved. Polling is available for environments where a persistent connection does not work. See Architecture . |
| Real-time config update listener, then activate |
watch
a config, or subscribe to the stream or flow for its key. It emits the current value and then every change. Nothing has to be activated.
|
| Values persist on the device across restarts |
Client SDKs keep the last values they received on the device and serve them on the next launch until live values arrive, with the evaluation reason
cached
. An app keeps one set per client SDK key, for the last context it connected with, so the first launch, or a launch with another context such as another signed-in user, reads the in-code default value until live values arrive; with a network they usually arrive in well under a second.
initialize
waits for live values for up to its timeout, 3 seconds by default, and the client keeps connecting in the background after a timeout.
|
| Value source: static, default, remote |
The
evaluation reason
:
found-match
when a live value from ConfigDirector was served,
cached
when a value kept on the device from an earlier launch was, or a reason such as
client-not-ready
,
config-state-missing
, or
type-mismatch
when the in-code default value was. Every SDK exposes it, through a hook or an evaluation method.
|
| Firebase installation as the evaluated entity |
The
context
: give it the user's identifier when they sign in, or leave the identifier out for an anonymous context, for which ConfigDirector derives an identifier that lasts until the app is uninstalled or the site's data is cleared. A context of another kind, such as a
device
, sets
kind
.
|
| Server-side Remote Config, in the Admin SDK | The server SDKs , with a server SDK key. They receive the targeting rules and evaluate every context locally. |
| Pricing: 100,000 fetches a day free, then per fetch | A free allowance of 1,000 monthly active users, then per user. Each distinct user, device, app install, or browser your apps evaluate configs for counts once a month, however many values it reads or updates it receives. See Pricing and billing . |
| Firebase Remote Config SDK | ConfigDirector SDK |
|---|---|
Flutter (
firebase_remote_config
)
|
Flutter |
| Android | Android , for Kotlin and Java, with a Jetpack Compose artifact |
| Apple platforms | Swift |
| Web | JavaScript , React , Vue , Next.js , Nuxt |
| React Native (community library) | React Native |
| Server-side Remote Config | Node.js , Python , Java , .NET , Go |
| Unity, C++ | Not available |
| LaunchDarkly | ConfigDirector |
|---|---|
| Project | Project |
| Environment | Environment . A critical environment in LaunchDarkly is a live environment in ConfigDirector. |
| Feature flag |
Config
, with a
role
:
Feature flag
for a temporary boolean,
Kill switch
for a permanent boolean,
Experiment
for variations you compare, and
Config
for everything else.
|
| Flag type: boolean, string, number, JSON |
Config
type
:
Boolean
,
String
,
Integer
or
Float
,
JSON
. ConfigDirector also has
Enum
,
URL
, and
Timespan
, which validate the value as that type. A string flag with a fixed set of variations is usually an
Enum
.
|
| Variations | The values a config serves. Experiments define them as named variations ; other roles enter the value in each targeting rule. |
| Temporary and permanent flags |
The
role
: a temporary boolean flag is a
Feature flag
and a permanent one a
Kill switch
, since the role decides the
lifetime
for every role but
Config
. Temporary configs are tracked through the
config lifecycle
, which tells you when they have settled and can be removed.
|
| Flag key | Config key . LaunchDarkly keys are valid ConfigDirector keys, so keep them: the code change is then only the SDK call. Unlike LaunchDarkly, a key can be renamed safely later, even in production. |
| Client-side SDK availability, mobile key availability | SDK availability : client SDKs, server SDKs, or both. Client and mobile applications both use the client SDK key. |
| Tags | Tags |
| JSON Schema on a flag's variations |
JSON Schema validation
on a
JSON
config, on both pricing options. Changing the schema re-validates every value already set in every environment.
|
| Flag maintainer, custom properties, flag links | No equivalent. Put the owner in the description, or in a tag. |
| Archived flag | Archived config. It can be restored for 30 days, and then it is purged. |
| LaunchDarkly | ConfigDirector |
|---|---|
| Default rule (fallthrough) | The default targeting rule , the last rule in every environment. Its value is served when no other rule matches. |
| Targeting on and off, with the off variation |
There is no on/off switch above the rules. To turn a flag off for everyone, remove or reorder its rules so the default targeting rule serves the off value. For a switch that stays independent of the rules, create a
Kill switch
and check it first in your code.
|
| Individual targets |
A conditional rule with the condition
identifier is one of
the listed identifiers. Add a
context.kind
condition to the rule when the identifiers belong to a context kind other than
user
.
|
| Rule with clauses | A conditional rule with one attribute condition per clause. Every condition of a rule must match, as in LaunchDarkly. There is no OR inside a rule: write a second rule, or use a segment, whose condition groups are combined with OR. |
| Attribute operators: string, number, semver, date, regex | Attribute conditions read a trait as text, a number, a semantic version, a datetime, an array, or a boolean, each with its own operators. There is no regular expression operator. Text conditions are case-sensitive. |
| Percentage rollout, bucketed by a chosen context kind and attribute |
A
percentage rollout
, on its own or as the value of a conditional rule. Contexts are assigned by their context kind and identifier. Choosing another attribute to bucket by is not available: evaluate with the entity you want to bucket by as the context instead, for example
kind: "organization"
.
|
| Segment, rule-based, per environment | A segment , defined once per project with one or more condition groups, used by any config in the project. An environment that needs its own definition gets an environment override . |
| Segment, list-based |
Not yet available. Use a condition group with
identifier is one of
the listed identifiers; it is kept in one place and reused the same way.
|
| Prerequisites | Not available. Put the condition the prerequisite flag expressed on the dependent flag's own rules, or check both flags in code. |
| Scheduled changes, approvals, guarded rollouts | Not available. Changes take effect as soon as they are saved. |
| Test run | The targeting rules tester , which evaluates saved or unsaved rules against a context and shows why each rule matched or not. |
| LaunchDarkly | ConfigDirector |
|---|---|
| Context | Context |
Context kind:
user
,
organization
,
device
, custom
|
Context kind
. Leaving it out means
user
. Any lowercase name of up to 64 letters, digits, dashes, or underscores works.
|
Context
key
|
Identifier
,
id
in the SDKs. A context is identified by its kind and identifier together, so user
42
and device
42
are different contexts.
|
Context
name
|
name
|
Custom attributes, such as
email
or
plan
|
Traits
, an arbitrary JSON object. Targeting rules address a trait with a JSON pointer, such as
/plan
or
/address/country
.
|
anonymous: true
|
An
anonymous context
: a context given without an identifier, or with
anonymous
set. It is evaluated but never stored or shown in the dashboard.
|
| Multi-context, several kinds in one evaluation |
Not available. Each evaluation is for one context. To target a user by their organization, copy the organization's attributes you target by into the user's traits, for example
/organization/plan
. Or evaluate the config a second time with the organization as the context.
|
| Private attributes | Not available. Only put the traits your targeting rules use in the context. |
| LaunchDarkly | ConfigDirector |
|---|---|
| SDK key | Server SDK key , a secret, for server SDKs. |
| Client-side ID and mobile key | Client SDK key , for browser and mobile SDKs. It is not secret, because client SDKs only receive evaluated values. |
| Streaming by default, with polling as an option | The same. See Architecture . |
| Server SDKs evaluate locally | The same. Server SDKs receive the rules and segments and evaluate every context in memory. |
| Client SDKs receive evaluated values | The same. |
| Fallback value in code | The in-code default value , passed with every read. It is returned only when the SDK cannot evaluate the config. |
| Flag change listeners |
watch
in the JavaScript SDKs, a stream or flow in the mobile SDKs, and the
configsUpdated
hook. Each SDK page shows them.
|
Bootstrapping from
localStorage
or the server
|
Client SDKs keep the last values they received on the device, in the browser's
localStorage
, and serve them on the next launch with the same context until live values arrive. Keeping them is on by default, with no bootstrap option to set, and the client is ready only once live values arrive. A server-rendered payload cannot be passed to the browser SDK: the
Next.js
and
Nuxt
SDKs evaluate configs during server-side rendering, so the first render carries real values.
|
| Relay Proxy |
Not needed. Every SDK connects to ConfigDirector directly over streaming. A base
url
option is available for an HTTP proxy of your own.
|
| Test data sources | The test client in each SDK's testing entry point, and the in-memory providers of the OpenFeature SDKs. See Test your code on each SDK page. |
| Experimentation metrics and results |
Not available. An
Experiment
config serves the variations; measure them in your own analytics. Every evaluation carries a
valueId
, a stable identifier of the value served, that you can send instead of the value itself.
|
| LaunchDarkly SDK | ConfigDirector SDK |
|---|---|
| JavaScript client | JavaScript |
| React Web | React |
| Vue | Vue |
| React Native | React Native |
| Flutter | Flutter |
| iOS | Swift |
| Android | Android |
| Node.js server, Python, Java, .NET server, Go | Node.js , Python , Java , .NET , Go |
| Next.js integration | Next.js . ConfigDirector also has a Nuxt SDK. |
| OpenFeature providers | OpenFeature providers for the web, Swift, Android, Flutter, Node.js, Python, Java, .NET, and Go |
| Group | Received by |
|---|---|
| Application requests, SDK versions, config lifecycle | Everyone in the organization: viewers, operators, developers, admins, and owners |
| Billing | Owners, admins, and billing managers |
| Integrations | Owners and admins |
| Quiet window | Minimum | Maximum | Until there is enough history |
|---|---|---|---|
| Archive Ready | 4 days | 45 days | 7 days |
| Old keys | 35 days | None | 35 days |
| Application request alerts | 1 hour | 7 days | 24 hours |
| In-code default alerts | 1 day | 14 days | 7 days |
| Outdated SDK version alerts | 1 day | 14 days | 5 days |
| SDK cannot evaluate segments alerts | 1 day | 14 days | 7 days |
| State | Applies to | Meaning |
|---|---|---|
| New | All configs | The config was created and has not been evaluated in any environment yet. |
| In use | All configs | The config has been evaluated in at least one environment and has not gone quiet. |
| Stale | All configs | The config was created more than 15 days ago and has never been evaluated. |
| Settled | Temporary only | The config has served a single value in every live environment long enough that it can be hardcoded and removed. |
| Archive Ready | Temporary only | The config was in use and its live environments have not evaluated it for its quiet window, which is sized from how often it is usually evaluated. |
| Role | Horizon |
|---|---|
| Feature flag | 7 days |
| Experiment | 14 days |
| Config | 30 days |
| Kill switch | Never settles |
| Control | Effect |
|---|---|
setValue(key, value)
|
Stores the value and, once the client is connected, delivers an update carrying only
key
. Watchers of
key
,
configsUpdated
handlers, and reads see it at once.
|
removeValue(key)
|
Removes the value and delivers a full update without it. Reads return the in-code default value with the
config-state-missing
reason, watchers of
key
receive the default, and
configsUpdated
lists
key
in
removedKeys
.
|
replaceValues(values)
|
Replaces every stored value, disarms any armed hold or failure, and delivers a full update. Use it to reset a test client shared across tests. |
holdInitialization()
|
The next
initialize
waits until
completeInitialization()
or
failInitialization()
, or until the client's
timeout
elapses.
|
completeInitialization()
|
Delivers the stored values to the held
initialize
, which completes with the client ready. Called while a hold is armed but not picked up, it disarms the hold.
|
failInitialization()
|
Fails the held
initialize
the way an invalid SDK key does: it completes promptly, the client is not ready,
connectionError
fires, and an error is logged. Called with no
initialize
held, it arms the next one to fail.
|
holdContextUpdate()
,
completeContextUpdate()
,
failContextUpdate()
|
The same for the next
updateContext
.
|
contextUpdates
|
The context of every
initialize
and
updateContext
call, in order.
resumeNetwork
is not recorded.
|
my-config-key: {value}
); } export default YourComponent; ``` You can also determine if the client is still initializing. This can be useful in the event of a slow connection where retrieving the initial config values may be slow, so rather than transition from the in-code default value to the evaluated value, you can show a loading state until the client is ready and config values are evaluated: ```tsx [YourComponent.tsx] import { useConfigValue } from "@configdirector/react-web-sdk"; function YourComponent() { const { value, loading } = useConfigValue("my-config", "default value"); if (loading) { returnLoading...
; } else { returnMy config value: {value}
; } } export default YourComponent; ``` ## Update the context The browser connects with the context given to the provider's `context` prop. Give it there when you already know the context as the page loads, so the first connection carries it: ```tsx [main.tsx] import { createRoot } from "react-dom/client" import App from "./App" import { ConfigDirectorProvider } from "@configdirector/react-web-sdk"; createRoot(document.getElementById("root")!).render(My config value: {myConfigValue}
A more complex component
; } export default YourComponent; ```| Artifact | Contents |
|---|---|
com.configdirector:android-sdk
|
The Android SDK |
com.configdirector:android-sdk-compose
|
Jetpack Compose bindings for the Android SDK |
com.configdirector:android-sdk-testing
|
Tools for testing code that uses the Android SDK |
com.configdirector:openfeature-android-provider
|
The OpenFeature Android provider |
com.configdirector:server-sdk
|
The Java server SDK |
com.configdirector:server-sdk-testing
|
Tools for testing code that uses the Java server SDK |
com.configdirector:openfeature-server-provider
|
The OpenFeature Java provider |
| Name on Maven Central | Name in this repository |
|---|---|
configdirector-android
|
android-sdk
|
configdirector-android-compose
|
android-sdk-compose
|
configdirector-android-testing
|
android-sdk-testing
|
configdirector-openfeature-android-provider
|
openfeature-android-provider
|
configdirector-server-sdk
|
server-sdk
|
configdirector-server-sdk-testing
|
server-sdk-testing
|
configdirector-openfeature-server-provider
|
openfeature-server-provider
|
my-config-key: {value}
); } export default YourComponent; ``` Retrieving config values in server routes: ```ts [route.ts] import { getConfigClient } from "@configdirector/nextjs-sdk/server"; export async function GET() { const client = getConfigClient(); const value = client.getValue("my-config-key", false); return Response.json({ "my-config-key": value }); } ``` ### `evaluate` Both halves can return the evaluation behind a value instead of the value alone: the value, whether it is the in-code default value, the `reason`, and the `valueId`. In client components, the client from the `useClient` hook of `@configdirector/nextjs-sdk/client` has `evaluate(key, defaultValue)`, as described for the [JavaScript SDK](https://docs.configdirector.com/sdks/browser/javascript#evaluate). The browser client exists only once the provider has mounted in the browser, and `useClient` throws before that, including during server rendering, so render a component that calls it only when `useConfigDirectorStatus` no longer reports `loading`. On the server, the client from `getConfigClient` has `evaluate(key, defaultValue, context)`, with the context optional as in `getValue`, as described for the [Node.js SDK](https://docs.configdirector.com/sdks/server/node-js#evaluate). Use it where the reason matters at the point of the read, such as when reporting an evaluation to another system. Both entry points export the `ConfigEvaluation` and `EvaluationReason` types, and `evaluate` is available from version 1.13.0 of the SDK. ```ts [route.ts] import { getConfigClient } from "@configdirector/nextjs-sdk/server"; export async function GET() { const evaluation = getConfigClient().evaluate("new-checkout", false, { id: "user-id" }); return Response.json({ newCheckout: evaluation.value, reason: evaluation.reason }); } ``` ### SSR config evaluation Evaluation of config values during server side rendering (SSR) utilizes the global *server* instance of the ConfigDirector Node.js client. That means there are no additional network requests that take place since the server SDK evaluates targeting rules locally for any given context.my-config-key: {String(value)}
| Artifact | Contents | Minimum SDK | Java bytecode |
|---|---|---|---|
com.configdirector:android-sdk
|
The SDK | 21 | 8 |
com.configdirector:android-sdk-compose
|
Optional Jetpack Compose bindings | 21 | 11 |
com.configdirector:android-sdk-testing
|
Tools for testing the code that reads your configs | 21 | 8 |
| Control | Effect |
|---|---|
setValue(key, value)
|
Stores the value and, once the client is connected, delivers an update carrying only
key
. Reads see it when
setValue
returns; watches of
key
and
ConfigsUpdated
listeners see it once the Main dispatcher runs them.
|
removeValue(key)
|
Removes the value and delivers a full update without it. Reads return the in-code default value with the
CONFIG_STATE_MISSING
reason, watches of
key
are handed the default, and
ConfigsUpdated
lists
key
in
removedKeys
.
|
replaceValues(values)
|
Replaces every stored value, disarms any armed hold or failure, and delivers a full update. Use it to reset a test client shared across tests. |
holdInitialization()
|
The next
initialize
waits until
completeInitialization()
or
failInitialization()
, or until the client's
timeoutMillis
elapses.
|
completeInitialization()
|
Delivers the stored values to the held
initialize
, so the client is ready when it returns, and lets
initialize
complete. Called while a hold is armed but not picked up, it disarms the hold.
|
failInitialization()
|
Fails the held
initialize
the way an invalid SDK key does: it completes promptly, the client is not ready, and an error is logged. Called with no
initialize
held, it arms the next one to fail.
|
holdContextUpdate()
,
completeContextUpdate()
,
failContextUpdate()
|
The same for the next
updateContext
.
|
contextUpdates
|
The context of every
initialize
and
updateContext
call, in order.
initialize
without a context records an empty context, and
resumeNetwork
is not recorded.
|