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.mdFor 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 directoryWORKDIR /goff
# Copy relay proxy configurationCOPY 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 portEXPOSE 1031
# Start the relay proxy with our configurationCMD ["--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 portlisten: 1031host: 0.0.0.0
# Flag retriever configuration - where to load flags fromretriever: 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 configurationrestApiTimeout: 5000
# OpenFeature Remote Evaluation Protocol (OFREP) supportenableOFREP: true
# Swagger UI (disable in production)enableSwaggerUI: falseAlternative 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: 10000S3 Retriever (load flags from AWS S3):
retriever: kind: s3 bucket: your-bucket-name item: flags/flags.yamlGitHub Retriever (load flags from GitHub repository):
retriever: kind: github repositorySlug: your-org/your-repo branch: main path: flags.yaml token: ${GITHUB_TOKEN} # Use environment variableGoogle Cloud Storage Retriever:
retriever: kind: googleStorage bucket: your-gcs-bucket object: flags/flags.yamlFeature 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 flagdark-mode: variations: enabled: true disabled: false defaultRule: variation: disabled
# Percentage rollout flagnew-checkout-flow: variations: enabled: true disabled: false defaultRule: percentage: enabled: 25 disabled: 75
# User targeting flagpremium-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 rolloutnew-algorithm: variations: v2: "new-algorithm" v1: "legacy-algorithm" defaultRule: progressiveRollout: initial: variation: v1 end: variation: v2 date: 2025-02-01T00:00:00Z percentage: 100Flag Rule Syntax
GO Feature Flag uses a powerful query language for targeting rules:
# Exact matchquery: email eq "admin@example.com"
# Containsquery: email co "@company.com"
# Starts withquery: username sw "admin_"
# Numeric comparisonquery: age ge 21
# Boolean checkquery: 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 listquery: country in ["US", "CA", "UK"]Deploying on Klutch.sh
Follow these steps to deploy GO Feature Flag on Klutch.sh:
-
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”.
-
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.
-
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 retrieverAWS_ACCESS_KEY_ID: AWS credentials for S3 retrieverAWS_SECRET_ACCESS_KEY: AWS secret for S3 retrieverGOOGLE_APPLICATION_CREDENTIALS: Path to GCP service account JSON
-
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)
-
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:
curl https://example-app.klutch.sh/healthExpected response:
{"initialized":true}Get All Flags:
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:
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:
npm install @openfeature/server-sdk @openfeature/go-feature-flag-providerConfigure 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:
pip install openfeature-sdk gofeatureflag-python-providerConfigure and use:
from openfeature import apifrom openfeature.contrib.provider.gofeatureflag import GoFeatureFlagProviderfrom openfeature.evaluation_context import EvaluationContext
# Configure the providerprovider = GoFeatureFlagProvider( endpoint="https://example-app.klutch.sh")
# Set the provider globallyapi.set_provider(provider)
# Get a clientclient = api.get_client()
# Create evaluation contextcontext = EvaluationContext( targeting_key="user-123", attributes={ "email": "user@example.com", "plan": "premium", "country": "US" })
# Evaluate flagsdark_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 detailsdetails = client.get_boolean_details("new-checkout-flow", False, context)print(f"New checkout: {details.value}, reason: {details.reason}")Go
Install the SDK:
go get github.com/open-feature/go-sdkgo get github.com/open-feature/go-sdk-contrib/providers/go-feature-flagConfigure 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:
composer require open-feature/sdk open-feature/go-feature-flag-providerConfigure 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:
gem install openfeature-sdkgem install openfeature-go-feature-flag-providerConfigure and use:
require 'openfeature/sdk'require 'openfeature/go-feature-flag-provider'
# Configure the providerprovider = OpenFeature::GoFeatureFlag::Provider.new( endpoint: 'https://example-app.klutch.sh')
# Register the providerOpenFeature::SDK.configure do |config| config.set_provider(provider)end
# Get a clientclient = OpenFeature::SDK.build_client
# Create evaluation contextcontext = OpenFeature::SDK::EvaluationContext.new( targeting_key: 'user-123', email: 'user@example.com', plan: 'premium', country: 'US')
# Evaluate flagsdark_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:
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:
exporter: kind: webhook endpointUrl: https://your-analytics-endpoint.com/events flushInterval: 60000 maxEventInMemory: 10000Authentication
Protect your relay proxy with API key authentication:
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: 60000Production 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
listenport ingoff-proxy.yamlmatches 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
pollingIntervalsetting (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/allflagsendpoint to debug flag evaluation results
Additional Resources
- Official GO Feature Flag Documentation
- GO Feature Flag GitHub Repository
- OpenFeature Specification
- Relay Proxy Configuration Reference
- Flag Configuration Format
- Flagsmith on Klutch.sh (alternative feature flag solution)
- Flipt on Klutch.sh (alternative feature flag solution)
- Klutch.sh Monitoring
- Klutch.sh Persistent Volumes