Skip to content

Deploying GO Feature Flag

Introduction

GO Feature Flag is a lightweight, open-source feature flag solution written in Go. Unlike traditional feature flag platforms that require complex infrastructure, GO Feature Flag stores your flags in a simple configuration file that can be hosted anywhere—from a local file to S3, Google Cloud Storage, GitHub, or an HTTP endpoint. The relay proxy component acts as a centralized server that evaluates flags and serves them to your applications via a REST API or OpenFeature-compliant SDKs.

What makes GO Feature Flag stand out is its simplicity. There’s no database to manage, no complex admin UI required, and the entire flag configuration lives in version-controlled YAML or JSON files. This makes it perfect for teams that want feature flag capabilities without the operational overhead of running a full-fledged feature management platform.

The relay proxy supports advanced features including percentage-based rollouts, user targeting with custom rules, scheduled flag changes, A/B testing with experimentation data export, and webhooks for flag change notifications. With official SDKs available for Go, JavaScript/TypeScript, Python, Java, .NET, PHP, and more, integrating GO Feature Flag into your existing stack is straightforward.

This guide walks you through deploying the GO Feature Flag relay proxy on Klutch.sh, configuring your feature flags, and integrating the SDKs into your applications for real-time flag evaluation.


Why Deploy GO Feature Flag on Klutch.sh

Deploying GO Feature Flag on Klutch.sh provides several advantages for modern development teams:

Simplified Infrastructure: Klutch.sh automatically detects your Dockerfile and handles the build and deployment process. No need to configure CI/CD pipelines or manage container orchestration.

Centralized Flag Evaluation: Running the relay proxy on Klutch.sh gives all your applications a single endpoint for flag evaluation. Whether you have microservices, mobile apps, or frontend applications, they all connect to the same reliable flag service.

High Availability: Your feature flags are critical infrastructure—if the flag service goes down, your applications may not function correctly. Klutch.sh ensures your relay proxy stays online with automatic health checks and restarts.

GitHub Integration: Connect your repository directly from GitHub. When you update your flag configuration and push changes, Klutch.sh automatically redeploys with the new configuration.

Environment Variables: Securely configure API keys, retriever URLs, and other settings through Klutch.sh’s environment variable management without exposing sensitive data in your repository.

Custom Domains: Assign a memorable domain to your flag service endpoint, making it easy for your team to remember and configure in their applications.

Persistent Storage: For advanced configurations that write data (like experimentation results), attach persistent volumes to ensure data survives container restarts.

Cost Effective: GO Feature Flag’s minimal resource requirements mean you can run a production-ready feature flag service on small instances, keeping infrastructure costs low.


Prerequisites

Before deploying GO Feature Flag on Klutch.sh, ensure you have:

  • A Klutch.sh account
  • A GitHub account with a repository for your configuration
  • Basic understanding of feature flags and progressive rollout concepts
  • Familiarity with YAML configuration files
  • (Optional) A flag configuration file hosted on S3, GCS, GitHub, or HTTP endpoint
  • (Optional) Docker installed locally for testing

Understanding GO Feature Flag Architecture

GO Feature Flag consists of two main components:

Flag Configuration File: A YAML, JSON, or TOML file that defines all your feature flags, their rules, and targeting conditions. This file can be stored locally, in cloud storage (S3, GCS), or fetched from an HTTP endpoint.

Relay Proxy: A lightweight Go server that reads the flag configuration, evaluates flags based on user context, and exposes a REST API and OpenFeature-compliant endpoints for your applications.

The relay proxy periodically polls your flag configuration source for changes, so you can update flags without redeploying the proxy. This architecture separates flag management from flag evaluation, giving you flexibility in how you manage your configuration.


Project Structure

A typical repository structure for deploying GO Feature Flag on Klutch.sh:

go-feature-flag-deployment/
├── Dockerfile
├── goff-proxy.yaml # Relay proxy configuration
├── flags.yaml # Feature flag definitions (if using local file)
└── README.md

For production deployments, you may want to store your flags.yaml in a separate repository or cloud storage to enable flag updates without redeploying the proxy.


Sample Dockerfile

Create a Dockerfile in the root of your repository. Klutch.sh automatically detects and uses it for deployment:

FROM thomaspoignant/go-feature-flag:latest
# Set working directory
WORKDIR /goff
# Copy relay proxy configuration
COPY goff-proxy.yaml /goff/goff-proxy.yaml
# Copy flag configuration (if using local file retriever)
COPY flags.yaml /goff/flags.yaml
# Expose the relay proxy port
EXPOSE 1031
# Start the relay proxy with our configuration
CMD ["--config", "/goff/goff-proxy.yaml"]

This Dockerfile uses the official GO Feature Flag image and copies your configuration files into the container.


Relay Proxy Configuration

Create goff-proxy.yaml in your repository root. This file configures the relay proxy server:

# goff-proxy.yaml - GO Feature Flag Relay Proxy Configuration
# Server listening port
listen: 1031
host: 0.0.0.0
# Flag retriever configuration - where to load flags from
retriever:
kind: file
path: /goff/flags.yaml
# Polling interval for flag updates (in milliseconds)
pollingInterval: 30000
# Enable debug logging (set to false in production)
debug: false
# REST API configuration
restApiTimeout: 5000
# OpenFeature Remote Evaluation Protocol (OFREP) support
enableOFREP: true
# Swagger UI (disable in production)
enableSwaggerUI: false

Alternative Retrievers

GO Feature Flag supports multiple retriever types. Here are common configurations:

HTTP Retriever (load flags from a URL):

retriever:
kind: http
url: https://raw.githubusercontent.com/your-org/flags/main/flags.yaml
timeout: 10000

S3 Retriever (load flags from AWS S3):

retriever:
kind: s3
bucket: your-bucket-name
item: flags/flags.yaml

GitHub Retriever (load flags from GitHub repository):

retriever:
kind: github
repositorySlug: your-org/your-repo
branch: main
path: flags.yaml
token: ${GITHUB_TOKEN} # Use environment variable

Google Cloud Storage Retriever:

retriever:
kind: googleStorage
bucket: your-gcs-bucket
object: flags/flags.yaml

Feature Flag Configuration

Create flags.yaml to define your feature flags. This is the core configuration that controls feature availability:

# flags.yaml - Feature Flag Definitions
# Simple boolean flag
dark-mode:
variations:
enabled: true
disabled: false
defaultRule:
variation: disabled
# Percentage rollout flag
new-checkout-flow:
variations:
enabled: true
disabled: false
defaultRule:
percentage:
enabled: 25
disabled: 75
# User targeting flag
premium-features:
variations:
full: "all-features"
limited: "basic-features"
none: "no-features"
targeting:
- name: premium-users
query: plan eq "premium"
variation: full
- name: trial-users
query: plan eq "trial"
variation: limited
defaultRule:
variation: none
# Scheduled flag (enables on specific date)
holiday-theme:
variations:
enabled: true
disabled: false
defaultRule:
variation: disabled
scheduledRollout:
- date: 2025-12-20T00:00:00Z
variation: enabled
- date: 2025-12-27T00:00:00Z
variation: disabled
# Progressive rollout
new-algorithm:
variations:
v2: "new-algorithm"
v1: "legacy-algorithm"
defaultRule:
progressiveRollout:
initial:
variation: v1
end:
variation: v2
date: 2025-02-01T00:00:00Z
percentage: 100

Flag Rule Syntax

GO Feature Flag uses a powerful query language for targeting rules:

# Exact match
query: email eq "admin@example.com"
# Contains
query: email co "@company.com"
# Starts with
query: username sw "admin_"
# Numeric comparison
query: age ge 21
# Boolean check
query: premium eq true
# Multiple conditions (AND)
query: plan eq "premium" and country eq "US"
# Multiple conditions (OR)
query: role eq "admin" or role eq "superuser"
# In list
query: country in ["US", "CA", "UK"]

Deploying on Klutch.sh

Follow these steps to deploy GO Feature Flag on Klutch.sh:

  1. Create a New Project

    Navigate to the Klutch.sh dashboard and create a new project. Name it something descriptive like “go-feature-flag” or “feature-flags-production”.

  2. Connect Your GitHub Repository

    Link your GitHub account if you haven’t already, then select the repository containing your GO Feature Flag configuration. Klutch.sh will automatically detect the Dockerfile.

  3. Configure Environment Variables

    If you’re using a retriever that requires credentials (GitHub, S3, GCS), add the necessary environment variables:

    • GITHUB_TOKEN: Personal access token for GitHub retriever
    • AWS_ACCESS_KEY_ID: AWS credentials for S3 retriever
    • AWS_SECRET_ACCESS_KEY: AWS secret for S3 retriever
    • GOOGLE_APPLICATION_CREDENTIALS: Path to GCP service account JSON
  4. Set Traffic Type and Port

    In the deployment settings, configure:

    • Traffic Type: Select HTTP
    • Internal Port: Set to 1031 (GO Feature Flag’s default port)
  5. Deploy

    Click the deploy button. Klutch.sh will build your Docker image and start the relay proxy.

Once deployed, your GO Feature Flag relay proxy will be available at your Klutch.sh app URL, such as example-app.klutch.sh.


Testing Your Deployment

After deployment, verify the relay proxy is running correctly:

Health Check:

Terminal window
curl https://example-app.klutch.sh/health

Expected response:

{"initialized":true}

Get All Flags:

Terminal window
curl https://example-app.klutch.sh/v1/allflags \
-H "Content-Type: application/json" \
-d '{
"evaluationContext": {
"key": "user-123",
"custom": {
"email": "user@example.com",
"plan": "premium"
}
}
}'

Evaluate Single Flag:

Terminal window
curl -X POST https://example-app.klutch.sh/ofrep/v1/evaluate/flags/dark-mode \
-H "Content-Type: application/json" \
-d '{
"context": {
"targetingKey": "user-123"
}
}'

SDK Integration

GO Feature Flag provides official SDKs for multiple languages. Here’s how to integrate them with your deployed relay proxy.

Node.js / JavaScript

Install the SDK:

Terminal window
npm install @openfeature/server-sdk @openfeature/go-feature-flag-provider

Configure and use:

const { OpenFeature } = require('@openfeature/server-sdk');
const { GoFeatureFlagProvider } = require('@openfeature/go-feature-flag-provider');
async function main() {
// Configure the provider to use your Klutch.sh deployment
const provider = new GoFeatureFlagProvider({
endpoint: 'https://example-app.klutch.sh',
});
// Register the provider with OpenFeature
await OpenFeature.setProviderAndWait(provider);
// Get a client for flag evaluation
const client = OpenFeature.getClient();
// Create evaluation context for the user
const context = {
targetingKey: 'user-123',
email: 'user@example.com',
plan: 'premium',
country: 'US',
};
// Evaluate a boolean flag
const darkModeEnabled = await client.getBooleanValue('dark-mode', false, context);
console.log(`Dark mode enabled: ${darkModeEnabled}`);
// Evaluate a string flag
const features = await client.getStringValue('premium-features', 'none', context);
console.log(`Features level: ${features}`);
// Evaluate with details (includes reason and variant)
const details = await client.getBooleanDetails('new-checkout-flow', false, context);
console.log(`New checkout: ${details.value}, reason: ${details.reason}`);
}
main().catch(console.error);

Python

Install the SDK:

Terminal window
pip install openfeature-sdk gofeatureflag-python-provider

Configure and use:

from openfeature import api
from openfeature.contrib.provider.gofeatureflag import GoFeatureFlagProvider
from openfeature.evaluation_context import EvaluationContext
# Configure the provider
provider = GoFeatureFlagProvider(
endpoint="https://example-app.klutch.sh"
)
# Set the provider globally
api.set_provider(provider)
# Get a client
client = api.get_client()
# Create evaluation context
context = EvaluationContext(
targeting_key="user-123",
attributes={
"email": "user@example.com",
"plan": "premium",
"country": "US"
}
)
# Evaluate flags
dark_mode = client.get_boolean_value("dark-mode", False, context)
print(f"Dark mode enabled: {dark_mode}")
features = client.get_string_value("premium-features", "none", context)
print(f"Features level: {features}")
# Evaluate with details
details = client.get_boolean_details("new-checkout-flow", False, context)
print(f"New checkout: {details.value}, reason: {details.reason}")

Go

Install the SDK:

Terminal window
go get github.com/open-feature/go-sdk
go get github.com/open-feature/go-sdk-contrib/providers/go-feature-flag

Configure and use:

package main
import (
"context"
"fmt"
"log"
"github.com/open-feature/go-sdk/openfeature"
gofeatureflag "github.com/open-feature/go-sdk-contrib/providers/go-feature-flag/pkg"
)
func main() {
// Configure the provider
provider, err := gofeatureflag.NewProvider(gofeatureflag.ProviderOptions{
Endpoint: "https://example-app.klutch.sh",
})
if err != nil {
log.Fatal(err)
}
// Register the provider
openfeature.SetProvider(provider)
// Get a client
client := openfeature.NewClient("my-app")
// Create evaluation context
evalCtx := openfeature.NewEvaluationContext(
"user-123",
map[string]interface{}{
"email": "user@example.com",
"plan": "premium",
"country": "US",
},
)
// Evaluate boolean flag
darkMode, err := client.BooleanValue(context.Background(), "dark-mode", false, evalCtx)
if err != nil {
log.Printf("Error evaluating flag: %v", err)
}
fmt.Printf("Dark mode enabled: %v\n", darkMode)
// Evaluate string flag
features, err := client.StringValue(context.Background(), "premium-features", "none", evalCtx)
if err != nil {
log.Printf("Error evaluating flag: %v", err)
}
fmt.Printf("Features level: %s\n", features)
// Evaluate with details
details, err := client.BooleanValueDetails(context.Background(), "new-checkout-flow", false, evalCtx)
if err != nil {
log.Printf("Error evaluating flag: %v", err)
}
fmt.Printf("New checkout: %v, reason: %s\n", details.Value, details.Reason)
}

Java

Add the dependency to your pom.xml:

<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>dev.openfeature.contrib.providers</groupId>
<artifactId>go-feature-flag</artifactId>
<version>0.2.8</version>
</dependency>

Configure and use:

import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.MutableContext;
import dev.openfeature.contrib.providers.gofeatureflag.GoFeatureFlagProvider;
import dev.openfeature.contrib.providers.gofeatureflag.GoFeatureFlagProviderOptions;
public class FeatureFlagExample {
public static void main(String[] args) {
// Configure the provider
GoFeatureFlagProviderOptions options = GoFeatureFlagProviderOptions.builder()
.endpoint("https://example-app.klutch.sh")
.build();
GoFeatureFlagProvider provider = new GoFeatureFlagProvider(options);
// Register the provider
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(provider);
// Get a client
Client client = api.getClient();
// Create evaluation context
MutableContext context = new MutableContext("user-123");
context.add("email", "user@example.com");
context.add("plan", "premium");
context.add("country", "US");
// Evaluate flags
boolean darkMode = client.getBooleanValue("dark-mode", false, context);
System.out.println("Dark mode enabled: " + darkMode);
String features = client.getStringValue("premium-features", "none", context);
System.out.println("Features level: " + features);
}
}

PHP

Install the SDK:

Terminal window
composer require open-feature/sdk open-feature/go-feature-flag-provider

Configure and use:

<?php
require_once 'vendor/autoload.php';
use OpenFeature\OpenFeatureAPI;
use OpenFeature\Providers\GoFeatureFlag\GoFeatureFlagProvider;
use OpenFeature\implementation\flags\MutableEvaluationContext;
// Configure the provider
$provider = new GoFeatureFlagProvider([
'endpoint' => 'https://example-app.klutch.sh'
]);
// Register the provider
$api = OpenFeatureAPI::getInstance();
$api->setProvider($provider);
// Get a client
$client = $api->getClient();
// Create evaluation context
$context = new MutableEvaluationContext('user-123', [
'email' => 'user@example.com',
'plan' => 'premium',
'country' => 'US'
]);
// Evaluate flags
$darkMode = $client->getBooleanValue('dark-mode', false, $context);
echo "Dark mode enabled: " . ($darkMode ? 'true' : 'false') . "\n";
$features = $client->getStringValue('premium-features', 'none', $context);
echo "Features level: " . $features . "\n";

Ruby

Install the SDK:

Terminal window
gem install openfeature-sdk
gem install openfeature-go-feature-flag-provider

Configure and use:

require 'openfeature/sdk'
require 'openfeature/go-feature-flag-provider'
# Configure the provider
provider = OpenFeature::GoFeatureFlag::Provider.new(
endpoint: 'https://example-app.klutch.sh'
)
# Register the provider
OpenFeature::SDK.configure do |config|
config.set_provider(provider)
end
# Get a client
client = OpenFeature::SDK.build_client
# Create evaluation context
context = OpenFeature::SDK::EvaluationContext.new(
targeting_key: 'user-123',
email: 'user@example.com',
plan: 'premium',
country: 'US'
)
# Evaluate flags
dark_mode = client.fetch_boolean_value(flag_key: 'dark-mode', default_value: false, evaluation_context: context)
puts "Dark mode enabled: #{dark_mode}"
features = client.fetch_string_value(flag_key: 'premium-features', default_value: 'none', evaluation_context: context)
puts "Features level: #{features}"

Advanced Configuration

Webhooks for Flag Changes

Configure webhooks to notify external services when flags are evaluated:

goff-proxy.yaml
notifiers:
- kind: webhook
endpointUrl: https://your-webhook-endpoint.com/flags
secret: ${WEBHOOK_SECRET}

Data Export for Analytics

Export flag evaluation data for analytics and experimentation:

goff-proxy.yaml
exporter:
kind: webhook
endpointUrl: https://your-analytics-endpoint.com/events
flushInterval: 60000
maxEventInMemory: 10000

Authentication

Protect your relay proxy with API key authentication:

goff-proxy.yaml
authorizedKeys:
evaluation:
- ${API_KEY_1}
- ${API_KEY_2}

Then include the header in SDK configuration:

const provider = new GoFeatureFlagProvider({
endpoint: 'https://example-app.klutch.sh',
apiKey: 'your-api-key',
});

Persistent Storage for Data Export

If using the data exporter, attach a persistent volume:

  • Mount Path: /data
  • Size: Based on your expected data volume (start with 5GB)

Update your configuration:

exporter:
kind: file
outputDir: /data/exports
flushInterval: 60000

Production Best Practices

Version Control Your Flags: Store your flags.yaml in Git. This gives you audit trails, rollback capabilities, and enables code review for flag changes.

Use Remote Retrievers: For production, use S3, GCS, or GitHub retrievers instead of local files. This allows you to update flags without redeploying the relay proxy.

Implement Gradual Rollouts: Use percentage-based rollouts for new features. Start with 5-10% of users and gradually increase as you gain confidence.

Set Default Values: Always configure sensible defaults in your SDK integration. If the flag service is unavailable, your application should degrade gracefully.

Monitor Flag Usage: Use the Monitoring features in Klutch.sh to track relay proxy health and response times.

Clean Up Old Flags: Regularly review and remove flags that are no longer needed. Stale flags increase complexity and evaluation overhead.

Test Flag Configurations: Before deploying flag changes to production, test them in a staging environment to ensure targeting rules work as expected.

Use Consistent Targeting Keys: Always use the same targetingKey (usually user ID) for a given user across all SDK calls to ensure consistent flag evaluation.


Troubleshooting

502 Bad Gateway

Cause: The relay proxy isn’t running or isn’t listening on the configured port.

Solutions:

  • Verify the listen port in goff-proxy.yaml matches the Internal Port in Klutch.sh (default: 1031)
  • Check deployment logs in Klutch.sh for startup errors
  • Ensure the Dockerfile CMD correctly references your configuration file

Flags Not Updating

Cause: The relay proxy caches flag configurations based on the polling interval.

Solutions:

  • Check the pollingInterval setting (default is 30000ms / 30 seconds)
  • For immediate updates, redeploy the application
  • If using remote retrievers, verify the file was actually updated in storage

Authentication Errors with Remote Retrievers

Cause: Missing or incorrect credentials for S3, GCS, or GitHub retrievers.

Solutions:

  • Verify environment variables are set correctly in Klutch.sh
  • For GitHub, ensure the token has read access to the repository
  • For S3/GCS, verify IAM permissions include read access to the bucket

SDK Connection Failures

Cause: Network issues or incorrect endpoint configuration.

Solutions:

  • Verify the endpoint URL includes the protocol (https://)
  • Test the endpoint directly with curl to ensure it’s reachable
  • Check for firewall rules blocking outbound connections from your application

Flag Evaluation Returning Defaults

Cause: The flag doesn’t exist, or targeting rules don’t match the evaluation context.

Solutions:

  • Verify the flag name matches exactly (case-sensitive)
  • Check that the evaluation context includes all attributes used in targeting rules
  • Use the /v1/allflags endpoint to debug flag evaluation results

Additional Resources