View as Markdown

CLI Installation & Authentication

Install the Mergify CLI and authenticate it to manage your merge queue, freezes, and stacked pull requests from the terminal.


The Mergify CLI lets you interact with Mergify features directly from your terminal. This page covers installation, authentication, and the exit codes commands return; for the commands themselves, see the CLI reference.

On macOS, the recommended way to install the CLI is through Mergify’s Homebrew tap:

Terminal window
brew install mergifyio/tap/mergify-cli

Upgrade with brew upgrade mergify-cli.

Linux and macOS (install script)

Section titled Linux and macOS (install script)

On Linux, or on macOS if you’d rather not use Homebrew, install with the official script:

Terminal window
curl -fsSL https://raw.githubusercontent.com/Mergifyio/mergify-cli/main/install.sh | sh

This installs mergify to ~/.local/bin. Set MERGIFY_INSTALL_DIR to pick a different location, or MERGIFY_VERSION to pin a specific release:

Terminal window
curl -fsSL https://raw.githubusercontent.com/Mergifyio/mergify-cli/main/install.sh | MERGIFY_INSTALL_DIR="$HOME/bin" sh

Once installed this way, upgrade with mergify self-update.

Download mergify-<version>-x86_64-pc-windows-msvc.zip from the latest release, extract it, and put mergify.exe anywhere on your PATH.

To install the CLI in a GitHub Actions workflow, use the Mergifyio/setup-cli action. It downloads the prebuilt mergify binary, verifies it against the release SHA256SUMS, and adds it to the PATH. No Python or extra toolchain is required, and it runs on Linux and macOS runners.

- uses: Mergifyio/setup-cli@v1
- run: mergify --version

By default the action installs a pinned version, which keeps your CI reproducible. Set the mergify_cli_version input to latest to install the newest release instead. The action also exposes the version it actually installed as the mergify_cli_version output:

- uses: Mergifyio/setup-cli@v1
id: setup-cli
with:
mergify_cli_version: latest
- run: echo "Installed mergify-cli ${{ steps.setup-cli.outputs.mergify_cli_version }}"

The CLI talks to two APIs, and they take different credentials:

  • The Mergify API backs mergify queue, mergify events, mergify freeze, mergify ci, mergify tests, and mergify config simulate. (mergify config validate needs no credential: it fetches the public schema and checks your file locally.)

  • The GitHub API backs Stacks, which creates and updates pull requests on GitHub directly.

mergify auth login covers the Mergify half. Stacks still needs a GitHub token of its own. The auth command reference lists the options each mergify auth command takes.

Terminal window
mergify auth login

The CLI opens the approval page in your browser and prints the URL and a short code. That URL carries the code, so the page opens with it already filled in: confirm it matches the one in your terminal, check the name on the token so you recognize the machine later, and authorize. The CLI picks up its credential and stores it. This is an OAuth 2.0 device authorization grant, so nothing listens on a local port and the browser does not have to be on the same machine. Over SSH or inside a container, open the printed URL on a machine that has one. Pass --no-browser to print the URL without opening a browser.

That name arrives filled in as Mergify CLI on <hostname>: the CLI reads the machine’s hostname and sends it when it opens the grant. --device-name sends a name of your choosing instead, and --device-name= sends none, leaving the token under a default every machine shares. The name travels with the grant, before anyone approves it, so editing the field on the approval page is too late to keep a hostname off Mergify — --device-name= is what does that.

What you get is a Mergify user token. It identifies you, reaches exactly what your dashboard session reaches, and is never sent to GitHub.

The CLI stores it in your operating system’s credential store: Keychain on macOS, the Secret Service on Linux, Credential Manager on Windows. Where none is available, on a headless container for instance, it falls back to a file in your configuration directory, restricted to your user. On a container image or a shared runner, treat that file as the secret it is.

mergify auth status reports whether this machine holds a credential:

Terminal window
mergify auth status

mergify auth logout revokes it on the server, not just on this machine:

Terminal window
mergify auth logout

You can also list and revoke your tokens under Settings > Developer > CLI Tokens in the dashboard. That list is personal, not per-organization: it shows the same tokens whichever organization you have selected. A token lasts a year, and you can hold 20 at a time. At that ceiling the approval page refuses the new login and tells you to revoke one, so watch the browser rather than the terminal if a sign-in never completes.

All three commands take --api-url, and so does every other command that calls the Mergify API:

Terminal window
mergify auth login --api-url https://mergify.example.com

Credentials are stored per API URL, so one machine can hold a login for the hosted service and one for an on-premise installation at the same time. That also means the URL has to match afterwards. A command that resolves a different API URL does not find the credential you stored, and fails unless --token or MERGIFY_TOKEN supplies one. Set MERGIFY_API_URL once instead of passing --api-url every time:

Terminal window
export MERGIFY_API_URL=https://mergify.example.com

mergify auth logout and mergify auth status are per URL too, so signing out of one installation leaves the other’s credential in place.

How Mergify API commands find a token

Section titled How Mergify API commands find a token

Commands that call the Mergify API resolve a credential in this order:

  1. The --token option on the command.
  2. The MERGIFY_TOKEN environment variable.
  3. The credential stored by mergify auth login, for that API URL.

A GitHub token is not on that list. If none of the three is set, the command stops and names the ways to get a Mergify credential, rather than sending something the API would refuse.

The mergify ci commands that call the API read a shorter list, because the endpoints they post to accept nothing but an application key. mergify ci scopes-send, mergify ci junit-process, and the deprecated mergify ci junit-upload skip step 3: they never read the credential mergify auth login stored, since those endpoints would refuse it anyway. Set MERGIFY_TOKEN to an application key for them, as the failure they print tells you to.

There is no global --token on mergify itself, so pass it to the subcommand:

Terminal window
mergify <command> --token your_token_here

Each command’s entry in the CLI reference lists the options it accepts, --token included.

mergify auth login is interactive, which makes it the wrong tool for a CI job. Unattended runs use an application key instead. Create one from your dashboard and set it as MERGIFY_TOKEN:

Terminal window
export MERGIFY_TOKEN=your_token_here

An application key can do what it was granted, resource by resource, and belongs to an organization rather than to a single repository. See Application key permissions. mergify ci junit-process (and the deprecated mergify ci junit-upload) and mergify ci scopes-send need a key granted CI Reporting, which a key granted Every resource does not hold. A user token from mergify auth login does not work for them either.

Each mergify tests command needs its own permission:

  • mergify tests show: a key that reads Tests.

  • mergify tests runs: a key that reads Tests, or one granted CI Reporting.

  • mergify tests quarantines list and mergify tests quarantines get: a key that reads Quarantines, or one granted CI Reporting. Both read the same quarantine list.

  • mergify tests quarantines add and mergify tests quarantines remove: a key granted Quarantines at Read & write.

Stacks commands act on pull requests through the GitHub API, so they need a GitHub token specifically. mergify auth login does not cover them, and a Mergify application key does not work here either.

They resolve that token on their own, in this order:

  1. The --token option on the command.
  2. The MERGIFY_TOKEN environment variable.
  3. GITHUB_TOKEN.
  4. gh auth token, from the GitHub CLI.

None of these has been dropped: a GitHub token is what the GitHub API takes.

Every source except --token is checked for the mut_ prefix of a Mergify user token before it is used. GitHub can only answer 401 to one of those, so it is skipped and the next source tried. That covers gh auth token as well, which echoes GITHUB_TOKEN when the variable is set. So exporting the credential mergify auth login stored does not break a Stacks command that has a real GitHub token further down the list. A --token you pass explicitly is sent as given.

If you have the GitHub CLI (gh) installed and authenticated, Stacks picks up its token automatically. Nothing else to configure. Otherwise, create a personal access token and set it as an environment variable:

Terminal window
export GITHUB_TOKEN=your_token_here

The CLI reports failures with these exit codes, so a CI job can tell a conflict apart from an API failure without parsing the output:

Code Name Meaning
0 Success Command completed successfully.
1 GenericError Unclassified runtime failure (I/O error, bug, or captured panic).
2 — Argument parsing or usage error.
3 StackNotFound Stack, branch, or commit not found.
4 Conflict Rebase or merge conflict.
5 GitHubApiError GitHub API request failed.
6 MergifyApiError Mergify API request failed.
7 InvalidState CLI invariant violated (e.g. command run outside a valid context).
8 ConfigurationError Configuration or credentials missing, unparseable, or failing validation.

Code 2 is the only one with no name. The argument parser produces it before any command runs, for an unknown flag or a missing argument, so there is no command-level error behind it to name.

Was this page helpful?