Use GitHub to Version Control Metric Definitions
This guide walks through how to make GitHub the source-of-truth of your metric definitions in GrowthBook.
Setting Up GrowthBook
For this guide, you can either use GrowthBook Cloud at https://app.growthbook.io or your own self-hosted deployment.
Connect to a Data Source
The easiest way to start is to use the built-in sample data in GrowthBook. Go to Experiments and in the Setup Steps, select the View Sample Experiment option. This will connect to a sample Postgres database and create a few sample metrics and an experiment.
If you have your own data warehouse, you can use that instead, but you will have to change the SQL queries further in this guide to match your specific data structure.
After connecting, you will need to find the data source id. The easiest way to find this is to go to Metrics and Data → Data Sources, click into the data source and copy the id from the last part of the URL. It will start with ds_
, for example ds_abc123
. Keep note of this id since you will need it later.
Create an API Key
Go to Settings → API Keys and click to create a new Secret Key. Make sure to select the "Admin" role since we will need to use it to create metrics.
Keep note of this key (it will start with secret_admin_
), you will need it later.
Setting up GitHub
First, create an empty GitHub repository. This is where we will define our metrics.
Create a metrics.yml
File
To keep things simple, we will store all of our metric definitions in a single YAML file.
We're going to use Fact Tables to define our metrics. This lets us write SQL once and re-use that across multiple metric definitions. We will create a single Fact Table for orders
and 2 metrics - purchased
and revenue
.
The format we're using below exactly matches what the GrowthBook API expects. If you want to store metrics in a different format, you will need to transform it first before sending to GrowthBook.
Create a new file in your GitHub repository called metrics.yml
with the following contents. Replace ds_abc123
with the id of your actual data source that you noted earlier.
factTables:
- id: orders
data:
name: Orders
datasource: ds_abc123
userIdTypes:
- user_id
sql: >
SELECT
userId as user_id,
amount,
received_at as timestamp
FROM orders
factMetrics:
- id: purchased
data:
name: Purchased
metricType: proportion
numerator:
factTableId: orders
- id: revenue
data:
name: Revenue
metricType: mean
numerator:
factTableId: orders
column: amount
Creating a Helper Script
Create a file named growthbook_sync.mjs
in your repo with the following contents (make sure to use the mjs
extension). If you are self-hosting GrowthBook, replace https://api.growthbook.io
with your self-hosted API host.
import { parse } from "yaml";
import fs from "fs";
// Edit these constants as needed
const FILE_NAME = 'metrics.yml';
const API_HOST = 'https://api.growthbook.io';
const GB_API_KEY = process.env.GB_API_KEY;
// Parse the yaml file
const file = fs.readFileSync(FILE_NAME, 'utf8');
const json = parse(file);
// Send to GrowthBook
const res = await fetch(`${API_HOST}/api/v1/bulk-import/facts`, {
method: "POST",
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${GB_API_KEY}`
},
body: JSON.stringify(json)
});
// Handle errors and print the response
const resJson = await res.json();
if (!res.ok) throw new Error(resJson?.message || "Error syncing");
console.log("Success!", resJson);
This script does 3 things:
- Parse the
metrics.yml
file into JSON - Send this payload to the GrowthBook API's
/bulk-import/facts
endpoint - Handle errors and print the response for easier debugging if things go wrong
Create a GitHub Secret
The script above follows best practices by using environment variables to store secrets. For this to work, you need to add a secret to GitHub.
In your GitHub repository settings, create a new secret called GB_API_KEY
and for the value, use the API Key you noted earlier (starting with secret_admin_
).
Set up GitHub Actions
We want the script above to run every time the metrics.yml
file changes. We can do this using GitHub Actions.
Create a file in your repository named .github/workflows/growthbook_sync.yml
with the following contents:
name: Sync to GrowthBook
on:
push:
branches:
- main
jobs:
growthbook_sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Sync to GrowthBook
run: |
npm install yaml
GB_API_KEY="${{secrets.GB_API_KEY}}" node growthbook_sync.mjs
Testing it Out
After comitting the above files to your GitHub repo, it should run automatically and you should see your new Orders fact table and 2 new metrics within your GrowthBook account. If it didn't work, look at the output of your GitHub Action to see if there are any error messages.
Making Changes
Fact Tables and Metrics created via this bulk-import
endpoint are marked as "Official" by default. This means they cannot be edited from within the GrowthBook UI and must be changed within GitHub instead. This helps avoid things getting out-of-sync.
You can still use the GrowthBook UI to create or edit other fact tables and metrics. Only "Official" ones created through this bulk-import
endpoint will be locked down.
Let's try updating the metrics.yml
file, maybe by adding a description to the Purchased metric:
# ...
data:
name: Purchased
description: Percent of people who purchased something
metricType: proportion
# ...
Commit this change to your main
branch and GrowthBook's copy of this metric will be updated to match, usually within 30 seconds!
Next Steps
Read the API Docs on the bulk-import/facts endpoint to see all of the options and fields you can use in your metrics.yml
file.