Integrations
GitHub Actions
Two GitHub Actions workflows run your project: one checks every branch, and one builds and publishes the datafiles when a change reaches main. With both in place, merging a pull request is how a change is released.
Create a project#
If you do not have one yet:
mkdir my-featurevisor-project && cd my-featurevisor-projectnpx @featurevisor/cli@latest initnpm installAdd a .nvmrc file containing the Node.js version used by the project:
24Checks#
This workflow runs for pull requests and for pushes to any branch but main or master, so problems show up before a merge:
name: Checkson: pull_request: push: branches-ignore: - main - masterpermissions: contents: readjobs: ci: name: Checks runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v7 - 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: Test specs run: npx featurevisor test - name: Build run: npx featurevisor buildMake this workflow a required status check in your branch protection rules, so a pull request cannot merge until lint, tests and the build pass.
Publish#
This workflow runs on every push to main or master. It checks again, builds, commits the state files and uploads the datafiles, in the order Deployment explains:
name: Publishon: push: branches: - main - masterpermissions: contents: writeconcurrency: group: featurevisor-publish cancel-in-progress: falsejobs: ci: name: Publish runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v7 with: ref: ${{ github.ref_name }} - 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: Test specs run: npx featurevisor test - name: Build run: npx featurevisor build - 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: Upload datafiles run: echo "Uploading..." # Replace this with your CDN upload command for the datafiles directory.Replace the last step with your host's upload command. GitHub Pages and Cloudflare Pages show complete ones.
- If the push is rejected because another merge landed first, run the workflow again from the latest
main. Never force push. - If the upload fails after the state was pushed, keep that state and run the upload again.
- The checks workflow only reads. The publish workflow asks for
contents: writeto push the state, and your organization must allow workflows to ask for it.
Sequential builds#
Two publish runs at once would start from the same state, so the concurrency group runs them one at a time:
- Use the same group in every workflow that writes state, and publish from one branch. Each run checks out that branch only once its turn comes.
- The group does not stop people pushing, and does not promise that a run builds the very latest commit.
- GitHub keeps one waiting run per group, and a newer one replaces it, even with
cancel-in-progress: false. Several quick merges can be published by one run. See GitHub's concurrency reference. - Branch protection and rulesets must allow the workflow's token to push the state commit.
contents: writealone does not get past them.
Related#
- Deployment, for the pipeline these workflows run
- GitHub Pages and Cloudflare Pages, for the upload step
- Testing before deployment


