Skip to content

OpenFeature Integration (OFREP)

st8d implements the OpenFeature Remote Evaluation Protocol (OFREP), which means any OpenFeature SDK can read st8 state as feature flags without a custom provider.

Each document key stored in st8 becomes a flag key. The document’s JSON content determines the flag’s value and type.

┌──────────────────┐ OFREP ┌──────────┐ ┌──────────┐
│ your app │ ───────▶ │ st8d │──▶│ disk │
│ (OpenFeature SDK)│ └──────────┘ └──────────┘
└──────────────────┘
  1. Your application uses any OpenFeature SDK with an OFREP provider.
  2. The provider calls st8d’s OFREP endpoints.
  3. st8d returns the current document values as typed flag evaluations.

Evaluate a single flag. Used by server-side (dynamic context) OFREP providers, which call this endpoint on every evaluation.

Query parameters:

ParameterDefaultDescription
namespacedefaultThe st8 namespace to read from
branchmainThe st8 branch to read from
prefix(none)Key prefix to prepend when looking up the document (see Key prefix)

Request body:

{
"context": {
"targetingKey": "user-123"
}
}

Response (200):

{
"key": "feature-x",
"value": true,
"reason": "STATIC",
"variant": "rev-4"
}

Response (404) — flag not found:

{
"key": "feature-x",
"errorCode": "FLAG_NOT_FOUND",
"errorDetails": "flag \"feature-x\" not found"
}

Evaluate all flags at once. Used by client-side (static context) OFREP providers, which cache all values locally after a single call.

Accepts the same ?namespace=, ?branch=, and ?prefix= query parameters.

Request body:

{
"context": {
"targetingKey": "user-123"
}
}

Response (200):

{
"flags": [
{"key": "feature-x", "value": true, "reason": "STATIC", "variant": "rev-4"},
{"key": "timeout", "value": 30, "reason": "STATIC", "variant": "rev-4"},
{"key": "theme", "value": "dark", "reason": "STATIC", "variant": "rev-4"}
],
"metadata": {"revision": 4}
}

Responds with 304 Not Modified if the client sends If-None-Match with the ETag from a previous response and the revision hasn’t changed.

The value type is inferred from the document content by JSON-parsing it:

Document contentOFREP typeExample
true or falsebooleantrue
Integer JSON numberinteger42
Fractional JSON numberfloat3.14
JSON stringstring"dark"
JSON object or arrayobject{"rate": 100}
Non-JSON textstringsome-plain-text

The evaluation reason is always STATIC — st8 stores values directly without targeting rules. The variant is the current revision ID (e.g. rev-4).

OFREP endpoints follow the same token-based auth as the rest of st8d. Provide a bearer token:

Authorization: Bearer <token>

Tokens need at least read permission for the target namespace and branch.

Terminal window
# Single flag
curl -s -X POST \
"http://localhost:8748/ofrep/v1/evaluate/flags/feature-x?namespace=myapp/prod&branch=main" \
-H "Authorization: Bearer my-token" \
-H "Content-Type: application/json" \
-d '{"context": {"targetingKey": "user-123"}}'
# All flags
curl -s -X POST \
"http://localhost:8748/ofrep/v1/evaluate/flags?namespace=myapp/prod&branch=main" \
-H "Authorization: Bearer my-token" \
-H "Content-Type: application/json" \
-d '{"context": {"targetingKey": "user-123"}}'

Point any OFREP provider at your st8d instance. The base URL should include the namespace and branch as query parameters — most providers let you set a custom base URL or path.

Find OFREP providers for your language at openfeature.dev/ecosystem.

Example (Go):

import (
ofrep "github.com/open-feature/go-sdk-contrib/providers/ofrep/pkg"
"github.com/open-feature/go-sdk/openfeature"
)
provider := ofrep.NewProvider(
"http://localhost:8748",
ofrep.WithBaseURLSuffix("?namespace=myapp/prod&branch=main"),
ofrep.WithBearerToken("my-token"),
)
openfeature.SetProvider(provider)

Once set up, evaluate flags the standard OpenFeature way:

client := openfeature.NewClient("my-service")
enabled, _ := client.BooleanValue(ctx, "feature-x", false, openfeature.NewEvaluationContext("user-123", nil))
timeout, _ := client.IntValue(ctx, "timeout", 30, openfeature.NewEvaluationContext("user-123", nil))

st8 does not have built-in targeting rules — all flags evaluate to STATIC. The evaluation context passed by the OpenFeature SDK is accepted by st8d but not used to vary the result.

For per-user targeting, use st8 branches to maintain separate flag sets and route your application to the correct branch based on the request context before calling the OpenFeature SDK.