Skip to content
Beta — Truss is in public beta. Documentation is actively updated but may not reflect the latest changes. Report issues on GitHub.

Feature Flags

Truss provides feature flag management powered by flagd (CNCF/OpenFeature). Manage flags, targeting rules, percentage rollouts, A/B variants, and segments from the dashboard. Client apps evaluate flags using standard OpenFeature SDKs.

Truss stores flag definitions in Postgres. When you create or update a flag, Truss syncs the configuration to flagd, which handles evaluation at the edge. Client SDKs connect to flagd via gRPC or HTTP for low-latency flag evaluation.

┌─────────────┐ ┌───────────┐ ┌───────────┐
│ Dashboard │─────▶│ Truss API │─────▶│ Postgres │
│ or API │ │ (Express) │ │ (source │
└─────────────┘ └─────┬─────┘ │ of truth)│
│ └─────┬─────┘
│ sync │
▼ ▼
┌───────────┐ ┌───────────┐
│ flagd │◀─────│ flag cfg │
│ (evaluator)│ │ (JSON) │
└─────┬─────┘ └───────────┘
gRPC / HTTP
┌─────▼─────┐
│ Your App │
│ (OF SDK) │
└───────────┘

Add these environment variables to your Truss deployment:

VariableDefaultDescription
FLAGD_HOSTlocalhostHostname of the flagd instance
FLAGD_PORT8013gRPC port for flagd evaluation
FLAGD_HTTP_PORT8016HTTP port for flagd evaluation (REST fallback)

If you are running Truss via Docker Compose, flagd runs as a sidecar container and these defaults work out of the box.

Truss supports four flag value types, matching the OpenFeature specification:

TypeExample defaultUse case
Booleantrue / falseKill switches, feature gates
String"banner-v2"UI variants, theme names
Number50Rate limits, thresholds, timeouts
Object{"color": "#9f1239", "size": "lg"}Complex configuration bundles

Navigate to Feature Flags in the sidebar. Click Create Flag and configure:

  • Key — unique identifier (e.g., new-checkout-flow)
  • Type — Boolean, String, Number, or Object
  • Default value — returned when no targeting rules match
  • Variants — named values the flag can resolve to (e.g., on/off, control/treatment)
  • State — ENABLED or DISABLED
  • Description — optional human-readable note
Terminal window
# Create a boolean feature flag
curl -X POST http://localhost:8787/api/flags \
-H "Content-Type: application/json" \
-d '{
"key": "new-checkout-flow",
"type": "boolean",
"description": "Enable the redesigned checkout experience",
"defaultVariant": "off",
"variants": {
"on": true,
"off": false
},
"state": "ENABLED"
}'
# Create a string flag with multiple variants
curl -X POST http://localhost:8787/api/flags \
-H "Content-Type: application/json" \
-d '{
"key": "hero-banner",
"type": "string",
"description": "A/B test for landing page hero",
"defaultVariant": "control",
"variants": {
"control": "banner-original",
"treatment-a": "banner-gradient",
"treatment-b": "banner-minimal"
},
"state": "ENABLED"
}'

Targeting rules let you return different flag variants based on evaluation context attributes (user ID, email, plan, country, etc.). Rules use JsonLogic expressions under the hood.

Match users by context attributes:

{
"if": [
{ "==": [{ "var": "plan" }, "pro"] },
"on",
"off"
]
}

Use starts_with, ends_with, and in for flexible string matching:

{
"if": [
{ "starts_with": [{ "var": "email" }, "admin@"] },
"on",
"off"
]
}
{
"if": [
{ "ends_with": [{ "var": "email" }, "@acme.com"] },
"on",
"off"
]
}

Target users based on app version using sem_ver:

{
"if": [
{ "sem_ver": [{ "var": "appVersion" }, ">=", "2.0.0"] },
"on",
"off"
]
}

Combine conditions with and / or:

{
"if": [
{
"and": [
{ "==": [{ "var": "plan" }, "pro"] },
{ "ends_with": [{ "var": "email" }, "@acme.com"] }
]
},
"on",
"off"
]
}
{
"if": [
{
"or": [
{ "==": [{ "var": "country" }, "US"] },
{ "==": [{ "var": "country" }, "CA"] }
]
},
"on",
"off"
]
}

Roll out a flag to a percentage of users using fractional. Bucketing is sticky based on the targeting key (typically user ID), so the same user always gets the same variant.

{
"fractional": [
{ "cat": [{ "var": "$flagd.flagKey" }, { "var": "targetingKey" }] },
["on", 25],
["off", 75]
]
}

This rolls out the on variant to 25% of users.

Split traffic across more than two variants:

{
"fractional": [
{ "cat": [{ "var": "$flagd.flagKey" }, { "var": "targetingKey" }] },
["control", 50],
["treatment-a", 25],
["treatment-b", 25]
]
}

Weights must sum to 100. The bucketing hash is deterministic — the same user always lands in the same bucket unless you change the seed or weights.

Segments are reusable targeting rules that can be shared across multiple flags. They use the $evaluators mechanism in flagd.

Navigate to Feature Flags > Segments. Click Create Segment and define:

  • Key — unique identifier (e.g., beta-testers)
  • Rules — JsonLogic expression that defines segment membership
Terminal window
curl -X POST http://localhost:8787/api/flags/segments \
-H "Content-Type: application/json" \
-d '{
"key": "beta-testers",
"rules": {
"or": [
{ "ends_with": [{ "var": "email" }, "@acme.com"] },
{ "in": [{ "var": "userId" }, ["user_001", "user_002", "user_003"]] }
]
}
}'

Reference a segment with $ref:

{
"if": [
{ "$ref": "beta-testers" },
"on",
"off"
]
}

Segments have full CRUD endpoints under /api/flags/segments. Each change re-syncs the flagd config so flag rules that $ref the segment pick up the new rules immediately.

MethodEndpointDescription
POST/api/flags/segmentsCreate a segment (segmentKey, name, description, rules).
PUT/api/flags/segments/:keyUpdate a segment’s name, description, or rules.
DELETE/api/flags/segments/:keyDelete a segment.
Terminal window
# Update a segment's rules
curl -X PUT http://localhost:8787/api/flags/segments/beta-testers \
-H "Content-Type: application/json" \
-d '{ "rules": { "ends_with": [{ "var": "email" }, "@acme.com"] } }'
# Delete a segment
curl -X DELETE http://localhost:8787/api/flags/segments/beta-testers

Flags support separate configurations per environment. Each environment maintains its own state, targeting rules, and default variants.

EnvironmentDescription
devLocal development — all flags default to ENABLED
stagingPre-production testing with production-like targeting
productionLive traffic — changes require confirmation
Terminal window
# Copy flag config from staging to production
curl -X POST http://localhost:8787/api/flags/new-checkout-flow/promote \
-H "Content-Type: application/json" \
-d '{
"from": "staging",
"to": "production"
}'

From the dashboard, use the Promote button on any flag’s detail page to copy its configuration between environments.

import { OpenFeature } from '@openfeature/server-sdk';
import { FlagdProvider } from '@openfeature/flagd-provider';
// Connect to flagd
OpenFeature.setProvider(new FlagdProvider({
host: 'localhost',
port: 8013,
}));
const client = OpenFeature.getClient();
// Boolean evaluation
const showCheckout = await client.getBooleanValue(
'new-checkout-flow',
false,
{ targetingKey: userId, plan: 'pro', email: user.email }
);
// String evaluation
const banner = await client.getStringValue(
'hero-banner',
'banner-original',
{ targetingKey: userId }
);
// Number evaluation
const rateLimit = await client.getNumberValue(
'api-rate-limit',
100,
{ targetingKey: userId, plan: user.plan }
);

For environments where an OpenFeature SDK is not available, evaluate flags directly through the Truss API:

Terminal window
# Evaluate a single flag
curl -X POST http://localhost:8787/api/flags/evaluate \
-H "Content-Type: application/json" \
-d '{
"flagKey": "new-checkout-flow",
"context": {
"targetingKey": "user_123",
"plan": "pro",
"email": "[email protected]"
}
}'

Response:

{
"key": "new-checkout-flow",
"variant": "on",
"value": true,
"reason": "TARGETING_MATCH"
}
Terminal window
# Bulk evaluate multiple flags
curl -X POST http://localhost:8787/api/flags/evaluate/bulk \
-H "Content-Type: application/json" \
-d '{
"flagKeys": ["new-checkout-flow", "hero-banner", "api-rate-limit"],
"context": {
"targetingKey": "user_123",
"plan": "pro"
}
}'

Truss flags are evaluated by flagd using the OpenFeature standard. Use any official OpenFeature SDK:

PlatformPackageInstall
JS (Web)@openfeature/web-sdk + @openfeature/flagd-web-providernpm i @openfeature/web-sdk @openfeature/flagd-web-provider
Node.js@openfeature/server-sdk + @openfeature/flagd-providernpm i @openfeature/server-sdk @openfeature/flagd-provider
React@openfeature/react-sdk + @openfeature/flagd-web-providernpm i @openfeature/react-sdk @openfeature/flagd-web-provider
Gogithub.com/open-feature/go-sdk + go-sdk-contrib/providers/flagdgo get github.com/open-feature/go-sdk github.com/open-feature/go-sdk-contrib/providers/flagd
Pythonopenfeature-sdk + openfeature-provider-flagdpip install openfeature-sdk openfeature-provider-flagd
Javadev.openfeature:sdk + dev.openfeature.contrib.providers:flagdSee Maven Central

All endpoints are prefixed with /api/flags. Authentication is required (session cookie or API key).

MethodEndpointDescription
GET/api/flagsList all flags
POST/api/flagsCreate a new flag
GET/api/flags/:keyGet flag by key
PUT/api/flags/:keyUpdate a flag
DELETE/api/flags/:keyDelete a flag
PATCH/api/flags/:key/toggleToggle flag state (ENABLED / DISABLED)
POST/api/flags/:key/promotePromote flag config between environments
POST/api/flags/evaluateEvaluate a single flag
POST/api/flags/evaluate/bulkEvaluate multiple flags
GET/api/flags/segmentsList all segments
POST/api/flags/segmentsCreate a segment
PUT/api/flags/segments/:keyUpdate a segment
DELETE/api/flags/segments/:keyDelete a segment