Migrate from Kodiak to Mergify
Map your .kodiak.toml automerge, blocking, and commit message settings to Mergify's Merge Queue.
Kodiak merges pull requests that carry an automerge label once they pass your GitHub branch protection. When that protection requires up-to-date branches, Kodiak updates each branch with its base just before merging it. Mergify’s Merge Queue does the same job, and adds batching, parallel checks, priorities, and scopes on top.
This page maps each .kodiak.toml option to its Mergify equivalent, and calls
out the few that have none.
How the Two Queues Compare
Section titled How the Two Queues CompareKodiak keeps one queue per target branch and works through it one pull request at a time: it updates the branch at the front of the queue if it is behind, waits for the required checks, merges it, then moves to the next one. A pull request joins that queue once it has its required approvals and no failing required check, and Kodiak only updates branches when Require branches to be up to date before merging is enabled.
Mergify’s queue also tests every pull request against the latest base branch before merging it, and it reads your branch protection the same way: by default, it injects your branch protection and ruleset requirements into the queue’s conditions, so you do not have to restate your required checks and reviews. Unlike Kodiak, Mergify does not have to test one pull request at a time.
To start with the behavior you have today, set
merge_queue.max_parallel_checks
to 1 and keep the default batch_size of 1. Mergify
then runs in-place checks:
it updates the pull request at the front of the queue with its base branch,
waits for CI, and merges it, like Kodiak. This mode also works
with Require branches to be up to date before
merging,
the setting Kodiak relies on to update branches, so you can switch without
touching your branch protection.
Typical Migration Plan
Section titled Typical Migration Plan-
Install the Mergify GitHub App on the repository and keep your branch protection as it is.
-
Add a
.mergify.ymlthat reproduces your.kodiak.toml, using the example below and the option mapping that follows it. -
Delete
.kodiak.toml(or.github/.kodiak.toml) in the same pull request so the two bots never race to merge the same pull request. If your organization’s.githubrepository also holds a.kodiak.toml, Kodiak falls back to it once the file is gone, so uninstall Kodiak from the repository instead of relying on the deletion. -
Once the queue runs as expected, turn on batches and parallel checks.
Side-by-Side Example
Section titled Side-by-Side ExampleA .kodiak.toml that squash-merges labeled pull requests into main unless
they carry a blocking label, and lets a hotfix label jump the queue:
version = 1
[merge]automerge_label = "ship it"method = "squash"blocking_labels = ["do not merge"]priority_merge_label = "hotfix"
[merge.message]title = "pull_request_title"body = "pull_request_body"strip_html_comments = trueinclude_coauthors = trueThe equivalent Mergify configuration:
merge_queue: max_parallel_checks: 1
merge_protections_settings: auto_merge_conditions: - label = ship it
merge_protections: - name: not blocked if: - base = main success_conditions: - -label = do not merge - "-title ~= ^WIP:"
queue_rules: - name: default merge_method: squash commit_message_format: title: pr-title body: pr-body trailers: - co-authored-by
priority_rules: - name: hotfix conditions: - label = hotfix priority: highThe merge protection holds the conditions
that Kodiak checks before it merges: Mergify merges a pull request only once
every active protection passes. Its if makes it apply to pull requests that
target main; if Kodiak merges into more than one branch, match them all with
a regex such as base ~= ^(main|develop)$.
Option Mapping
Section titled Option MappingTriggering a Merge
Section titled Triggering a Merge-
merge.automerge_label→auto_merge_conditionsqueues a pull request as soon as it carries the label, and removing the label dequeues it, as it does with Kodiak. Whenautomerge_labellists several labels, any one of them triggers a merge, so put them under anor:merge_protections_settings: auto_merge_conditions: - or: - label = ship it - label = merge it -
merge.require_automerge_label = false→auto_merge_conditions: true, which queues every pull request. Your merge protections and branch protection still decide when it merges. -
merge.automerge_dependencies→ for Dependabot, thedependabot-update-typecondition reads the update type from Dependabot’s commit message. Kodiak’sversions = ["minor", "patch"]becomes:merge_protections_settings: auto_merge_conditions: - or: - label = ship it - and: - author = dependabot[bot] - dependabot-update-type ~= ^version-update:semver-(minor|patch)$ - -dependabot-update-type = version-update:semver-majorA grouped update lists one update type per dependency and the
~=line matches if any of them does, so the last line keeps out a group that contains a major bump, as Kodiak does by going by the largest bump. Like Kodiak, this skips a Dependabot pull request whose update type it cannot read, since no value matches. Kodiak names bots without their[bot]suffix (dependabot), while Mergify’sauthorcondition uses the full login (dependabot[bot]).Kodiak also reads the update type from other bots’ pull requests, such as the version table in a Renovate description. Mergify reads Dependabot’s metadata only, so match other bots on their title with
title ~=.
Blocking a Merge
Section titled Blocking a MergeEach of these becomes a line in the merge protection’s success_conditions,
as in the example above.
-
merge.blocking_labels→-label = <name>, one line per label. -
merge.blocking_title_regex→-title ~= <regex>. Kodiak blocks titles matching^WIP:.*even when the option is not set, so the example above adds"-title ~= ^WIP:"to keep that behavior. Quote the condition when it ends with a colon, or YAML reads it as a key. -
merge.block_on_reviews_requested→"#review-requested = 0", if you used this deprecated option. -
merge.block_on_neutral_required_check_runs→check-success = <name>for that check. Unlike GitHub’s branch protection,check-successonly matches asuccessconclusion, so a neutral run blocks the merge. -
disable_bot_label(kodiak:disabled) → there is no single label that turns Mergify off on a pull request, but a-label = <name>line keeps Mergify from merging it.
Two Kodiak behaviors need nothing on the Mergify side:
-
Draft pull requests: neither Kodiak nor Mergify merges a draft.
-
merge.do_not_merge: leave outauto_merge_conditions, and Mergify merges a pull request only when somebody runs@mergifyio queueon it. To update a branch without merging it, comment@mergifyio update.
Merge Method and Commit Message
Section titled Merge Method and Commit Message-
merge.method→merge_methodon the queue rule:merge,squash, orrebase. Kodiak’srebase_fast_forward, which moves the base branch to the tested commits without rewriting them, is Mergify’sfast-forward. Left unset, Mergify uses a merge method the repository allows, as Kodiak does. -
kodiak: merge.method = '<method>'labels → add a queue rule for that method and route labeled pull requests to it withqueue_conditions. A pull request goes to the first queue rule whosequeue_conditionsit matches, so list it first:queue_rules: - name: rebase merge_method: rebase queue_conditions: - label = rebase - name: default merge_method: squash -
merge.message.*→commit_message_formaton the queue rule:Kodiak Mergify title = "github_default"title: inherit(the default)title = "pull_request_title",include_pr_number = truetitle: pr-title:{title} (#{number})body = "github_default"body: inherit(the default)body = "pull_request_body"body: pr-bodybody = "empty"body: emptyinclude_coauthors = truetrailers: [co-authored-by]strip_html_comments = truenothing to set: pr-bodyalways leaves out HTML commentsLike Kodiak’s coauthor options,
trailersneedsbodyset topr-bodyorempty.
Branch Updates
Section titled Branch Updates-
Updating at merge time → automatic. With in-place checks, the queue updates the pull request at its front by merging the base branch into it, which is what Kodiak does. Set
update_method: rebaseon the queue rule to rebase it instead. -
update.always,update.require_automerge_label,update.autoupdate_label, andmerge.update_branch_immediately→ not needed. Kodiak uses them to keep pull requests up to date before their turn in its queue. With in-place checks, Mergify updates a pull request when the queue tests it, which is the update the merge depends on. To bring a branch up to date by hand, comment@mergifyio updateon its pull request. -
update.ignored_usernames→ Kodiak drops such a pull request from its queue when it needs an update, because it may not touch the branch. Mergify’s in-place checks do update it; once you enable parallel checks, Mergify tests the pull request on a temporary branch and leaves its own branch alone. -
merge.optimistic_updates→ not needed. Kodiak uses it to choose between updating a pull request that is behind and waiting for its running checks first. Mergify’s queue updates the pull request when its turn comes and runs CI on the updated code, so there is nothing to choose.
Queue Order
Section titled Queue Order-
First come, first served → Mergify’s default: a pull request joins the end of the queue.
-
merge.priority_merge_label→ a priority rule withpriority: highon that label. By default the pull request is placed after the ones whose checks are already running; setallow_checks_interruption: trueto test it first. -
merge.prioritize_ready_to_merge→ no exact equivalent. Mergify keeps the queue order. Once the queue tests on batch pull requests, a pull request at the front of the queue that already contains the tip of the base branch merges without running CI again. See Direct Merge. -
merge.dont_wait_on_status_checks→ Kodiak waits briefly for these checks, then skips the pull request instead of blocking its queue. Mergify only waits for the checks your branch protection and conditions require, so do not require a check that may never finish. For a required check that can hang,checks_timeoutremoves the pull request from the queue after a while. By default, it derives that time from your recent CI runs; set a duration to choose it yourself:queue_rules: - name: default checks_timeout: 30 min
Conflicts and Cleanup
Section titled Conflicts and Cleanup-
merge.notify_on_conflict→ Mergify removes a pull request that conflicts with its base branch from the queue and says why in a comment. Unlike Kodiak, it leaves the label in place. -
merge.delete_branch_on_merge→ enable GitHub’s Automatically delete head branches repository setting. Kodiak stands aside when that setting is on, so you can enable it before you switch.
Options With No Equivalent
Section titled Options With No Equivalent-
approve.auto_approve_usernamesandapprove.auto_approve_labels: Mergify’s queue does not approve pull requests. They need the approvals your branch protection requires, whoever opened them. -
merge.message.include_pr_number = false:pr-titlealways appends the pull request number. -
merge.message.cut_body_before,cut_body_after, andcut_body_and_text:pr-bodyuses the whole description. Since it leaves out HTML comments, a pull request template can keep text out of the commit message by wrapping it in<!-- -->. -
merge.message.strip_html_comments = falseandbody_type:pr-bodyalways uses the Markdown description without its HTML comments. -
merge.message.include_pull_request_url: there is noPR-URL:trailer. The available trailers areco-authored-by,approved-by, andmerged-by. -
merge.message.include_pull_request_author: Kodiak’s own documentation describes it as no longer necessary.
Going Further
Section titled Going FurtherKodiak tests one pull request at a time, so the time to merge a queue of pull requests grows with its length. Once your queue runs on Mergify, you can change that:
-
Batches: test several pull requests in one CI run, and let Mergify split a failing batch to find the culprit.
-
Parallel checks: test the next pull requests in the queue while the first one is still running. Batches and parallel checks test on temporary batch pull requests, so they need Require branches to be up to date before merging turned off, or Mergify added as a bypass actor. Mergify still tests every pull request against the latest base branch.
-
Scopes: test and merge pull requests that touch unrelated parts of a monorepo independently.
-
Two-step CI: run a fast suite to enter the queue and the full suite only before the merge.
-
Merge Protections: beyond the rule above, freeze merges during a release, hold a pull request until another one merges with
Depends-On, or schedule a merge withMerge-After. -
Queue monitoring: see how long pull requests wait and where that time goes.
Was this page helpful?
Thanks for your feedback!