---
title: CLI Installation & Authentication
description: 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](/cli).

## Installation

### macOS (Homebrew)

On macOS, the recommended way to install the CLI is through Mergify's
[Homebrew tap](https://github.com/Mergifyio/homebrew-tap):

```bash
brew install mergifyio/tap/mergify-cli
```

Upgrade with `brew upgrade mergify-cli`.

### Linux and macOS (install script)

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

<CliInstall />

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

```bash
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`.

### Windows

Download `mergify-<version>-x86_64-pc-windows-msvc.zip` from the
[latest release](https://github.com/Mergifyio/mergify-cli/releases/latest),
extract it, and put `mergify.exe` anywhere on your `PATH`.

### GitHub Actions

To install the CLI in a GitHub Actions workflow, use the
[`Mergifyio/setup-cli`](https://github.com/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.

```yaml
- uses: Mergifyio/setup-cli@v2
- 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:

```yaml
- uses: Mergifyio/setup-cli@v2
  id: setup-cli
  with:
    mergify_cli_version: latest

- run: echo "Installed mergify-cli ${{ steps.setup-cli.outputs.mergify_cli_version }}"
```

:::tip
  Pinning a specific version is the default and works well with
  [Renovate](https://docs.renovatebot.com/), which can open pull requests to
  bump the version as new releases ship. Use `latest` only when you always want
  the most recent build.
:::

## Authentication

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](/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.

### Sign in to Mergify

```bash
mergify auth login
```

The CLI prints a URL and a short code. Open the URL, type the code in, give the
token a name 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](https://www.rfc-editor.org/rfc/rfc8628), so nothing listens on a local
port and the browser does not have to be on the same machine. It works over SSH
and inside containers.

What you get is a [Mergify user token](/api/usage#using-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:

```bash
mergify auth status
```

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

```bash
mergify auth logout
```

You can also list and revoke your tokens under **Settings > Developer > CLI
Tokens** in the [dashboard](https://dashboard.mergify.com). 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.

#### On-premise installations

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

```bash
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](/enterprise) 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 falls through to
the next source in the list below. Set `MERGIFY_API_URL` once instead of passing
`--api-url` every time:

```bash
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

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.
4. `GITHUB_TOKEN`. Deprecated.
5. `gh auth token`, from the GitHub CLI. Deprecated.

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

```bash
mergify <command> --token your_token_here
```

Each command's entry in the [CLI reference](/cli) lists the options it accepts,
`--token` included.

The stored credential deliberately outranks `GITHUB_TOKEN`, so a `GITHUB_TOKEN`
left exported in a shell cannot quietly override the account you signed in as.
`--token` and `MERGIFY_TOKEN` stay above it, so a CI job that sets either keeps
working unchanged.

:::caution
  Letting the CLI authenticate to the Mergify API with a GitHub token is
  deprecated. Both `GITHUB_TOKEN` and the `gh auth token` fallback still work,
  and the CLI warns when it uses one. Run `mergify auth login` instead, or set
  `MERGIFY_TOKEN` to an application key. This says nothing about Stacks, which
  needs a GitHub token and reads it exactly as before.
:::

### Application keys for CI

`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](https://dashboard.mergify.com) and set it as `MERGIFY_TOKEN`:

```bash
export MERGIFY_TOKEN=your_token_here
```

An application key carries either the `admin` scope or the `ci` scope, and
belongs to a GitHub account rather than to a single repository. See
[Application Key Scopes](/api/usage#application-key-scopes) for what each one
covers. `mergify ci junit-process` (and the deprecated `mergify ci junit-upload`)
and `mergify ci scopes-send` post to endpoints that accept nothing but a `ci`
key, so those commands need one specifically. A user token from
`mergify auth login` does not work for them.

### GitHub token for Stacks

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.

Nothing here is deprecated: a GitHub token is what the GitHub API takes.

If you have the [GitHub CLI](https://cli.github.com/) (`gh`) installed and
authenticated, Stacks picks up its token automatically. Nothing else to
configure. Otherwise, create a [personal access
token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
and set it as an environment variable:

```bash
export GITHUB_TOKEN=your_token_here
```

:::caution
  Stacks commands read `MERGIFY_TOKEN` before `GITHUB_TOKEN`, and a Mergify
  application key is not a GitHub token. If `MERGIFY_TOKEN` holds an
  application key, pass `--token` to your Stacks commands, or keep that key
  out of `MERGIFY_TOKEN`.
:::

## Exit Codes

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). |
| `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 file missing, unparseable, or failing validation. |
