Integrations
GitHub Pages
GitHub Pages can host your datafiles, and the Catalog beside them, published by a GitHub Actions workflow.
This page builds on GitHub Actions. Set up its project, .nvmrc and checks workflow first, then use the publish workflow below in place of the one there.
Publish the datafiles#
This workflow runs on every push to main or master. It checks, builds, pushes the state, then publishes the datafiles directory to GitHub Pages:
name: Publishon: push: branches: - main - master# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pagespermissions: contents: write pages: write id-token: writeconcurrency: group: featurevisor-publish cancel-in-progress: falsejobs: publish: name: Publish environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 with: ref: ${{ github.ref_name }} fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: npm - name: Install dependencies run: npm ci - name: Lint run: npx featurevisor lint - name: Build run: npx featurevisor build - name: Test specs run: npx featurevisor test - name: Git configs run: | git config user.name "${{ github.actor }}" git config user.email "${{ github.actor }}@users.noreply.github.com" - name: Push back to origin run: | git add -A .featurevisor if ! git diff --cached --quiet; then git commit -m "[skip ci] Revision $(cat .featurevisor/REVISION)" fi git push origin "HEAD:${{ github.ref_name }}" - name: Create index.html run: echo "<html><body>It works.</body></html>" > datafiles/index.html - name: Setup Pages uses: actions/configure-pages@v6 - name: Upload artifact uses: actions/upload-pages-artifact@v5 with: path: 'datafiles' - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v5The index.html step only gives the site a page at its root. The workflow pushes the state files before it deploys. If the push is rejected, run it again from the latest main and never force push. If the deployment fails, keep the pushed state and run it again. The concurrency and branch protection rules from GitHub Actions apply here too.
Each target's datafile is then at its path under the site:
https://<username>.github.io/<repo>/featurevisor-all.jsonhttps://<username>.github.io/<repo>/production/featurevisor-web.json, with environments
A custom domain replaces the first part of the URL. Applications fetch these URLs with an SDK.
Publish the Catalog#
To publish the Catalog beside the datafiles, export it into the datafiles directory before the upload. Use this workflow instead of the one above, not alongside it:
name: Publish with Catalogon: push: branches: - main - master# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pagespermissions: contents: write pages: write id-token: writeconcurrency: group: featurevisor-publish cancel-in-progress: falsejobs: publish: name: Publish environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 with: ref: ${{ github.ref_name }} fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v7 with: node-version-file: .nvmrc cache: npm - name: Install dependencies run: npm ci - name: Lint run: npx featurevisor lint - name: Build run: npx featurevisor build - name: Test specs and save report run: npx featurevisor test --json > test-report.json - name: Git configs run: | git config user.name "${{ github.actor }}" git config user.email "${{ github.actor }}@users.noreply.github.com" - name: Push back to origin run: | git add -A .featurevisor if ! git diff --cached --quiet; then git commit -m "[skip ci] Revision $(cat .featurevisor/REVISION)" fi git push origin "HEAD:${{ github.ref_name }}" - name: Export Catalog run: npx featurevisor catalog export --out-dir=./datafiles --hash-router --test-report=./test-report.json - name: Setup Pages uses: actions/configure-pages@v6 - name: Upload artifact uses: actions/upload-pages-artifact@v5 with: path: 'datafiles' - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v5Keep fetch-depth: 0 on checkout. Fetching the full history lets the exported Catalog show earlier changes, not only the latest commit.
For a user or organization Pages site, or a custom domain serving at its root, keep the default catalogBasePath: '/'. For a repository site, set catalogBasePath: '/your-repository-name/' in featurevisor.config.js. Hash routing lets direct entity links work without a server fallback.
Keep uploading the entire datafiles directory, including the generated Catalog HTML, assets and data. On a custom domain such as https://flags.example.com/, the Catalog opens at that URL, entity links use https://flags.example.com/#/features/checkout, and SDK datafiles remain at https://flags.example.com/featurevisor-all.json. Do not overwrite the generated index.html with the placeholder.
Use --hash-router because GitHub Pages serves a 404 page for missing paths. The fragment stays in the browser, so opening or refreshing an entity link requests the existing Catalog directory instead of a missing HTML file. A custom 404 page alone does not configure a successful HTML fallback.
Keep the order build, test, then catalog export, and do not rebuild or change definitions between the report and export, because the report's fingerprint includes the allocation state the build writes. A failed test must stop deployment.
Catalog exports include project definitions, Git history and the supplied test results. Reports can contain test contexts, expected values and actual values. A GitHub Pages site is public unless your plan offers access control for Pages, so a Catalog published this way shows every definition, unlaunched work included, to anyone with the URL. Use private hosting when that matters. Keep its generated UI and data together, and follow the export retention guidance when updating an existing deployment.

