Reference
SDKs and integrations
Use a FluxGate SDK for Java, TypeScript or Rust, an OpenFeature SDK with the OFREP provider for any other language, or plain HTTP.
Before you start
- The edge server is running, by default on port 8081, and the flag
express-checkoutis deployed to Development. See Clients and edge server. - You have a client and its SDK key. Server code uses
checkout-service, a Backend client. Browser code uses a Web client, because a browser sends anOriginheader. In the story, that client isjuniper-web.
FluxGate SDKs
FluxGate publishes SDKs for three ecosystems. All of them talk to the edge server over OFREP with an SDK key, so they work with any edge server that the Edge server API describes. Each one is open source under the Apache License 2.0.
| SDK | Packages | Registry | Source |
|---|---|---|---|
| Java and Spring Boot | com.forgeopslabs:fluxgate-java, com.forgeopslabs:fluxgate-spring-boot-starter | Maven Central | forgeopslabs/fluxgate-springboot |
| TypeScript, React and Angular | @forgeops/fluxgate, @forgeops/fluxgate-react, @forgeops/fluxgate-angular | npm | forgeopslabs/fluxgate-js |
| Rust | fluxgate | crates.io | forgeopslabs/fluxgate-rust |
The SDKs share one behavior, so you can move between them without surprises:
- Evaluations never throw. On any error, such as a network failure, a wrong SDK key or an unknown flag, you get your default value and an error code that says why.
- The default value sets the type. A string default expects a string flag. Another type returns your default with
TYPE_MISMATCH. - An off flag returns your default. A flag that is disabled or not deployed to the client's environment answers
falsewith no variant. For a string or number flag, the SDKs return your default value without an error. - A targeting key is required. Without one, the SDKs return your default with
TARGETING_KEY_MISSINGand do not call the edge. - Retries, timeouts and a short cache. Network errors and HTTP
502,503and504are retried with backoff. Successful single-flag results are cached for 30 seconds per flag and context. - OpenFeature providers included. Each SDK has an OpenFeature provider, so code written against the OpenFeature API can use FluxGate without changes.
Each repository has samples with a Docker Compose file that starts its own FluxGate stack and a script that creates the flags, so you can try the SDK on your machine.
Which one to use
| Your app | Use |
|---|---|
| Spring Boot 3.5 | fluxgate-spring-boot-starter: properties, @FeatureToggle, metrics and a health indicator. |
| Java 17 or newer, without Spring | fluxgate-java. |
| Node.js 20 or newer | @forgeops/fluxgate. |
| React 18 or newer | @forgeops/fluxgate-react, with a Web client. |
| Angular 19 or newer | @forgeops/fluxgate-angular, with a Web client. |
| Rust 1.85 or newer | fluxgate, async on Tokio or with the blocking feature. |
| Any other language | An OpenFeature SDK with the OFREP provider, below. |
| A script or a shell | Plain HTTP. |
OpenFeature with OFREP
OpenFeature is a vendor-neutral API for feature flags. OFREP, the OpenFeature remote evaluation protocol, is how an OpenFeature provider talks to a flag service over HTTP. The edge server speaks OFREP, so any language with an OpenFeature SDK works, even without a FluxGate SDK. You install the OpenFeature SDK for your language and its OFREP provider, and you point the provider at the edge.
Every example does the same four things:
- Create an OFREP provider with the edge's base URL, the root without a path, and the SDK key in the
Authorizationheader. - Register the provider with OpenFeature and wait until it is ready.
- Build an evaluation context with a targeting key and the attributes your rules use.
- Ask for the flag with a default value.
import { OpenFeature } from '@openfeature/server-sdk';
import { OFREPProvider } from '@openfeature/ofrep-provider';
await OpenFeature.setProviderAndWait(new OFREPProvider({
baseUrl: 'http://localhost:8081',
headers: [['Authorization', `Bearer ${process.env.FLUXGATE_SDK_KEY}`]],
}));
const client = OpenFeature.getClient();
const variant = await client.getStringValue('express-checkout', 'classic', {
targetingKey: 'user-1',
country: 'CA',
user_tier: 'plus',
});
console.log(`checkout: ${variant}`);
await OpenFeature.close();import { OpenFeature } from '@openfeature/web-sdk';
import { OFREPWebProvider } from '@openfeature/ofrep-web-provider';
const SDK_KEY = '<juniper-web SDK key>';
await OpenFeature.setContext({ targetingKey: 'user-1', country: 'CA', user_tier: 'plus' });
await OpenFeature.setProviderAndWait(new OFREPWebProvider({
baseUrl: 'http://localhost:8081',
headers: [['Authorization', `Bearer ${SDK_KEY}`]],
}));
const client = OpenFeature.getClient();
const variant = client.getStringValue('express-checkout', 'classic');
console.log(`checkout: ${variant}`);import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import dev.openfeature.contrib.providers.ofrep.OfrepProvider;
import dev.openfeature.contrib.providers.ofrep.OfrepProviderOptions;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.MutableContext;
import dev.openfeature.sdk.OpenFeatureAPI;
public class App {
public static void main(String[] args) throws Exception {
OfrepProviderOptions options = OfrepProviderOptions.builder()
.baseUrl("http://localhost:8081")
.headers(ImmutableMap.of(
"Authorization", ImmutableList.of("Bearer " + System.getenv("FLUXGATE_SDK_KEY"))))
.build();
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(OfrepProvider.constructProvider(options));
Client client = api.getClient();
MutableContext context = new MutableContext("user-1");
context.add("country", "CA");
context.add("user_tier", "plus");
String variant = client.getStringValue("express-checkout", "classic", context);
System.out.println("checkout: " + variant);
api.shutdown();
}
}Node (server)
Install the server SDK and the OFREP provider. Save the first tab above as app.mjs. It is an ES module, so keep the .mjs extension.
npm install @openfeature/server-sdk @openfeature/ofrep-providerFLUXGATE_SDK_KEY=<checkout-service SDK key> node app.mjscheckout: express- Pass
headersas a list of pairs, as above. A plain object fails when the provider starts, in the version below. setProviderAndWaitmakes sure the provider is ready before the first evaluation.- The evaluation context sits in the third argument.
targetingKeyis the bucketing key.countryanduser_tierare the context attributes from Contexts.
Tested with @openfeature/server-sdk 1.23.0 and @openfeature/ofrep-provider 0.2.5, on Node 22.
To see the full answer, not only the value, ask for the details:
const details = await client.getStringDetails('express-checkout', 'classic', {
targetingKey: 'user-1',
country: 'CA',
user_tier: 'plus',
});
console.log(details);{
value: 'express',
variant: 'express',
reason: 'TARGETING_MATCH',
flagMetadata: {},
flagKey: 'express-checkout'
}Browser (web)
A browser app uses the OpenFeature web SDK. The web provider is different from the server provider: it fetches all flags for one context with the bulk endpoint, POST /ofrep/v1/evaluate/flags, and then answers evaluations from memory. When you change the context, it fetches again.
A browser sends an Origin header, so the SDK key must belong to a Web client, and the page origin must be in the client's Web Origins. In the story, juniper-web allows http://localhost:5173. The edge answers any other origin with 403. See CORS.
Install the web SDK and the web provider. Put the second tab above in your app's entry file, for example main.js in a Vite project, and replace the placeholder with the SDK key of the Web client.
npm install @openfeature/web-sdk @openfeature/ofrep-web-providerThe console.log line prints this in the browser console:
checkout: express- Set the context before the provider. The provider reads the context when it starts and sends it in the bulk request.
getStringValueis synchronous. It reads the result that the provider fetched.- The SDK key of a Web client is visible to anyone who opens the page. Use a Web client only for flags that are safe to show, and rely on Web Origins to limit which sites can use the key.
The provider's own documentation describes more options: polling with pollInterval, a localStorage cache with cacheMode, and a re-fetch when the tab becomes visible again.
Tested with @openfeature/web-sdk 1.10.0 and @openfeature/ofrep-web-provider 0.4.3 (@openfeature/core 1.12.0 installs with them), in a page served from http://localhost:5174 by a Vite dev server. The page's origin was the only entry in the Web client's Web Origins. The browser sent a preflight request, which returned 204, and then the bulk request, which returned 200.
Java with the OFREP provider
Add the OpenFeature Java SDK and the OFREP provider to your build. The third tab above holds App.java. Set FLUXGATE_SDK_KEY to the checkout-service SDK key in the environment of the process, then run the App class from your IDE or build tool.
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>dev.openfeature.contrib.providers</groupId>
<artifactId>ofrep</artifactId>
<version>0.0.2</version>
</dependency>The program prints:
checkout: expressThe MutableContext constructor takes the targeting key. The provider needs Guava for ImmutableMap. It comes as a dependency of the OFREP provider. Add com.google.guava:guava yourself if you want to pin its version.
Tested with dev.openfeature:sdk 1.23.0 and dev.openfeature.contrib.providers:ofrep 0.0.2, the latest release of the provider on Maven Central when this page was written. The example compiled with Maven for Java 17 on a JDK 25 build (Temurin 25.0.1), and it printed checkout: express against a real edge server.
Good to know about the OFREP providers
- A failed evaluation does not throw. OpenFeature returns your default value. The details call shows why. With a wrong SDK key,
errorCodeisGENERALanderrorMessageisOFREP request failed: unauthorized. Check a new key withcurlfirst. - A flag that is not deployed to the client's environment answers
falsewith the reasonDISABLED. A string flag then returns your default value, becausefalseis not a string. The error code in the details isTYPE_MISMATCH. - An unknown flag key returns your default value with the error code
FLAG_NOT_FOUND. - Use the same type as the flag's values.
express-checkouthas string variants, so callgetStringValue.holiday-banneris an on/off flag, so callgetBooleanValue. - An SDK key belongs to one client, and a client belongs to one environment. A Development key never sees Production rules.
- The edge caches an accepted key for up to 300 seconds by default, so a rotated API key or a disabled client can keep working for that long.
Plain HTTP
If you use no SDK, send a POST request with curl or any HTTP client. A single-flag call looks like this:
curl -s -X POST http://localhost:8081/ofrep/v1/evaluate/flags/express-checkout \
-H "Authorization: Bearer $FLUXGATE_SDK_KEY" \
-H 'Content-Type: application/json' \
-d '{"context":{"targetingKey":"user-1","country":"CA","user_tier":"plus"}}'{"key":"express-checkout","value":"express","reason":"TARGETING_MATCH","variant":"express"}The Edge server API page describes the endpoints, the errors, CORS, and ETags in full.
Next
Pick your SDK: Java and Spring Boot, TypeScript, React and Angular, or Rust.