Skip to main content

Overview

In this guide you set up two GitHub Actions workflows for the web-app project: one runs shipd diff --exit-code on pull requests that touch your flag definitions, and one runs shipd push when it merges to main. Both authenticate with a service account token (shipd_sa_…), not a personal key. Prerequisites
  • Your flag config and generated output committed (shipd.config.ts and TypeScript types, or Go source and generated Go accessors). See Define flags in code.
  • For TypeScript, @shipdit/cli in your devDependencies. The Go workflow pins the shared CLI to 0.5.0 (the upcoming Go-support release); update that version to match your team once it is published.
  • Permission to create service accounts (organization admin or owner).

Create a service account token

Create a service account named github-actions, then create a token bound to the web-app project. Do not bind it to an environment: shipd push makes project-wide changes, and environment-bound credentials get 403 forbidden. Steps are in Create a service account. Use two tokens so pull request jobs cannot change flags: Add flag:archive only if the job runs shipd push --prune. Why each permission is needed is in Push permissions. Create a shipd-diff environment under Settings → Environments, require trusted reviewers, and store SHIPD_DIFF_TOKEN as an environment secret there. Review the pull request commit before approving this environment job: TypeScript and Go configs execute code, and Go tests execute pull-request code too. Restrict approval to trusted changes; do not approve untrusted fork jobs. The examples deliberately gate the whole diff job before it receives the token. Store SHIPD_PUSH_TOKEN as a repository secret under Settings → Secrets and variables → Actions for the protected main branch workflow. Both workflow examples use the file paths from Define flags in code. Go source selects Go output by default unless typesLanguage overrides it.

Check drift on pull requests

SHIPD_API_URL is required. Without it, a runner that never ran shipd login calls http://localhost:8000. shipd diff also reports flags that exist on the server but not in the file, as - archive flag, and counts them as drift. Add them to shipd.config.ts (or shipd pull) so the diff shows only your changes.

Push on main

  • --ci skips the confirmation prompt. CI=true, which GitHub Actions sets, does the same. Without either, push is cancelled in a non-interactive job.
  • concurrency stops two merges from pushing at once and conflicting with each other.
  • Pushing to production needs flag_production:toggle even for a default-only change.

Go projects

Use the same tokens, permission scopes, and exit codes. Install Go 1.23+ and Node.js 22.12+ on the runner. The CLI reads shipd.config.go directly and selects Go output by default unless typesLanguage overrides it. The workflows watch all Go source so edits to imported local helper packages also trigger them. Include any non-Go files those helpers read in the path filters, and adjust the output checks if you override typesLanguage or typesOut.
git ls-files fails if the generated output is not tracked. The first diff checks that committed accessors match the Go definitions; the CLI diff compares definitions with the server.

Handle exit codes 3 and 5

Do not add --force to CI. It overwrites changes made in the dashboard, and it cannot bypass approvals. The full exit code list is in the CLI reference.

Next steps