Feature flags quickstart
Define a new feature flag called
enablePaypal
on the Root
type:type Root {
exampleFlag: Boolean!
enablePaypal: Boolean!
}
Switch to the "Logic" tab and select the "Enable Paypal" flag.
Add an "If / Else" expression with a rule that enables the flag if
context > user > id
is test_id
and disables it by default.Switch to the Preview tab and enter the following query:
query TestQuery {
root {
enablePaypal
}
}
Hypertune uses GraphQL for its query language. In the result panel, you can see just the part of your configuration logic that matches your query.
Now pass the
context
argument containing the user
object in the query:query TestQuery {
root(
context: {
user: {
id: "test_id"
name: "Test"
email: "[email protected]"
}
}
) {
enablePaypal
}
}
Now you can see a more reduced version of your configuration logic, where the "If / Else" expression has been replaced with its result.
Click "Save and activate" in the navigation bar.
Open a terminal in the root of your TypeScript project and run:
npm install hypertune
Now add a new file in the root of your project called
hypertune.graphql
with the following contents:query InitQuery {
root {
enablePaypal
}
}
This is your SDK initialization query. It determines what configuration logic is downloaded when the SDK initializes or fetches an update. And you get auto-generated code, based on this query, to use the SDK with end-to-end type-safety.
Add another file in the root of your project called
hypertune.json
with the following contents:{
"projectId": your_project_id,
"token": "your_token",
}
Set
projectId
to your project ID from the Settings tab and token
to your token.You can also set
outputDirectoryPath
to control where Hypertune generates your code and queryFilePath
to control where Hypertune should find your SDK initialization query.If you don't want to commit your token, you can remove it from your
hypertune.json
and create a .env
file in the root of your project with an environment variable:HYPERTUNE_TOKEN=your_token
If you're using Hypertune on the frontend, you may need to prefix the variable name with
REACT_APP_
or NEXT_PUBLIC_
to expose it to the browser.Then run:
npx hypertune
You now have a generated TypeScript source file which you can use to interact with the SDK.
Add a new file called
hypertune.ts
with the following contents:import { initializeHypertune } from "./generated/project_0";
const hypertune = initializeHypertune({});
export default hypertune;
Replace
"./generated/project_0"
with the path to your generated file.Now you can import this top-level
hypertune
singleton and use its auto-generated type-safe methods to access your feature flag.React
Node.js
Add a new file called
useHypertune.ts
with the following contents:import React, { useEffect, useMemo } from "react";
import hypertune from "./hypertune";
export default function useHypertune() {
const [isInitialized, setIsInitialized] = React.useState<boolean>(
hypertune.isInitialized()
);
useEffect(() => {
hypertune.waitForInitialization().then(() => {
setIsInitialized(true);
});
}, []);
return useMemo(
() =>
hypertune
.root({
context: {
user: { id: "test_id", name: "Test", email: "[email protected]" },
},
}),
[]
);
}
Then use the hook in your app:
import useHypertune from "./useHypertune";
export default function App() {
const rootNode = useHypertune();
const enablePaypal = rootNode.enablePaypal({}).get(/* fallback */ false);
return (
<div>Enable Paypal: {String(enablePaypal)}</div>
);
}
import express, { Express } from "express";
import hypertune from "./hypertune";
export default function getApp(): Express {
const app = express();
app.get("/purchase", (req, res, next) => {
const rootNode = hypertune.root({
context: { user: { id: "test_id", name: "Test", email: "[email protected]" } },
});
const enablePaypal = rootNode.enablePaypal({}).get(/* fallback */ false);
if (enablePaypal) {
// Paypal code
}
});
return app;
}
If you're using Hypertune on the frontend and have a Content Security Policy, add the following URLs to the
connect-src
directive: https://edge.prod.hypertune.com https://gcp.fasthorse.workers.dev
This allows analytics to be sent back to Hypertune so you can see how often different parts of your flag logic are called, e.g. to see how many sessions fall into each targeting rule, as well as analytics for your events, A/B tests and machine learning loops.
When you ran
npx hypertune
, a snapshot of your configuration logic was saved in the generated file. The SDK instantly initializes from this snapshot first, before fetching the latest configuration logic from the server. So if you try accessing your flag just as your Node server or React app starts up, it'll use the logic in the snapshot if the SDK hasn't had a chance to initialize from the server yet.Optionally, you can explicitly wait for the SDK to initialize from the server with
hypertune.waitForInitialization()
:React
Node.JS
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
hypertune.waitForInitialization().then(() => {
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
});
app.get("/purchase", async (req, res, next) => {
await hypertune.waitForInitialization();
const rootNode = hypertune.root({
context: { user: { id: "test_id", name: "Test", email: "[email protected]" } },
});
const enablePaypal = rootNode.enablePaypal({}).get(/* fallback */ false);
if (enablePaypal) {
// Paypal code
}
});
If you've turned off
buildTimeFallback
in your hypertune.json
, your generated file won't have a snapshot so the SDK will use your hardcoded fallback values.Now you can update the logic for your
enablePaypal
flag from the Hypertune UI without a code update, build, deployment, app release or service restart.When you hit "Save and activate", the SDK will download your new logic and use it for the next evaluation.
The Logic tab shows you live counts of how often different parts of your configuration logic are evaluated.
To add another new field, define it in the schema, include it in your SDK initialization query and rerun code generation with
npx hypertune
.