Using Flagonic from Go
Flagonic has no Go SDK of its own — by design. You use the official OpenFeature Go SDK with its official OFREP provider. Nothing in your code imports anything Flagonic-specific, so swapping flag vendors later is a config change, not a refactor.
Prerequisites
- A running Flagonic server with a flag defined — see the overview & quickstart.
- An SDK key (
fgn_sdk_…) for your project + environment, minted in the dashboard or via the admin API. - Go 1.21 or newer.
Install
go get github.com/open-feature/go-sdk/openfeature
go get github.com/open-feature/go-sdk-contrib/providers/ofrep
Both modules are maintained by the OpenFeature project (a CNCF project), not by Flagonic.
Initialize once at startup
Point the OFREP provider at your Flagonic base URL, authenticating with the SDK key.
Set the provider once, early in main:
package main
import (
"context"
"log"
"os"
"github.com/open-feature/go-sdk-contrib/providers/ofrep"
"github.com/open-feature/go-sdk/openfeature"
)
func main() {
provider := ofrep.NewProvider(
os.Getenv("FLAGONIC_URL"), // e.g. https://flags.example.com
ofrep.WithBearerToken(os.Getenv("FLAGONIC_SDK_KEY")),
)
if err := openfeature.SetProviderAndWait(provider); err != nil {
log.Fatalf("set flag provider: %v", err)
}
client := openfeature.NewClient("checkout-service")
_ = client // use it everywhere flags are needed
}
Build an evaluation context
The evaluation context is what Flagonic's targeting rules and percentage rollouts match against. The targeting key should be a stable identifier for the subject (user ID, session ID, tenant ID) — it is what keeps a user inside a percentage rollout as you ramp it up.
evalCtx := openfeature.NewEvaluationContext(
"user-42", // targetingKey — stable per subject
map[string]interface{}{
"plan": "pro",
"email": "jo@example.com",
"build": 4217,
},
)
Every attribute you send is available to rule conditions
(eq, neq, in, not_in, contains,
starts_with, ends_with, gt, gte,
lt, lte, exists).
Evaluate flags
Each evaluation takes a default value, returned if the flag is missing or the server is unreachable — your code keeps working through outages:
ctx := context.Background()
enabled, _ := client.BooleanValue(ctx, "new-checkout", false, evalCtx)
if enabled {
// new code path
}
theme, _ := client.StringValue(ctx, "banner-theme", "default", evalCtx)
limit, _ := client.IntValue(ctx, "rate-limit", 100, evalCtx)
ratio, _ := client.FloatValue(ctx, "sampling-ratio", 0.1, evalCtx)
config, _ := client.ObjectValue(ctx, "checkout-config", map[string]interface{}{}, evalCtx)
The five methods map to Flagonic's flag types: boolean, string,
number (int or float), and object.
Inspect why a value was served
The …ValueDetails variants return the variant and the OpenFeature reason —
useful for logging and debugging targeting:
details, _ := client.BooleanValueDetails(ctx, "new-checkout", false, evalCtx)
log.Printf("value=%v variant=%s reason=%s",
details.Value, details.Variant, details.Reason)
TARGETING_MATCH | A rule's conditions matched the context. |
SPLIT | The subject fell inside a percentage rollout bucket. |
DEFAULT | Rules exist but none matched; the default variant was served. |
STATIC | The flag has no rules; the default variant was served. |
DISABLED | The flag is toggled off in this environment; the off variant was served. |
ERROR | Evaluation failed (flag missing, server unreachable); your default argument was returned. |
Worked example: gating an HTTP handler
func checkoutHandler(client *openfeature.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := userFrom(r) // however you authenticate
evalCtx := openfeature.NewEvaluationContext(user.ID,
map[string]interface{}{"plan": user.Plan})
if on, _ := client.BooleanValue(r.Context(), "new-checkout", false, evalCtx); on {
newCheckout(w, r)
return
}
legacyCheckout(w, r)
}
}
Production notes
- Set the provider once.
openfeature.SetProviderAndWaitat startup; create clients freely after that — they are cheap and safe for concurrent use. - Defaults are your safety net. Choose the value you would want during a Flagonic outage; evaluation errors return it rather than failing your request.
- Stable targeting keys. Percentage rollouts hash the targeting key per flag. Anonymous users need a sticky identifier (e.g. a session cookie) to get a consistent experience.
- One SDK key per service per environment makes revocation surgical — revoke a key in the dashboard and only that deployment loses access.
Switching vendors (yes, really)
Because the provider above speaks standard OFREP, pointing your service at any other OFREP-compatible backend is exactly this diff — no import changes, no code changes:
- FLAGONIC_URL=https://flags.example.com
+ FLAGONIC_URL=https://other-vendor.example.com
That door swings both ways: migrating to Flagonic from another OFREP backend is the same one-line change.