Skip to content

Hotfix Flow

martyy-code edited this page Aug 5, 2026 · 5 revisions

Last synced from docs/engineering/process/hotfix.md on 2026-08-05. The repo file is the source of truth. If the two diverge, follow the repo.

This page describes the hotfix flow for @deessejs/fp: when to use it, how it differs from the regular release pipeline, and what every contributor and release engineer needs to do.

A hotfix is the path used to ship an urgent production fix without dragging unfinished work from staging. It is the one exception to the rule that every PR targets staging first.

TL;DR

A hotfix cuts a hotfix/* branch from main, opens a PR against main directly (no Changeset on that PR), ships via a dedicated hotfix.yml workflow, back-merges main to staging, and finally opens a follow-up PR on staging that carries a Changeset describing the fix. The follow-up PR lands in the next regular release, where the changelog entry finally appears.

Outline

  1. When to use the hotfix flow
  2. The flow at a glance
  3. Cut the hotfix branch
  4. Open the hotfix PR against main
  5. Ship the hotfix
  6. Back-merge to staging
  7. Open the follow-up PR on staging
  8. Why the rule above all: every main merge is a release
  9. Related documents

1. When to use the hotfix flow

Use the hotfix flow when all of the following are true:

  • There is an urgent production bug that cannot wait for the next regular release.
  • staging contains work that is not ready to ship to production.
  • Merging staging into main to release the fix would drag the unfinished work along with it.

If the unfinished work in staging is ready to ship, the regular pipeline is faster end-to-end. The hotfix flow only earns its keep when the urgency justifies bypassing staging.

2. The flow at a glance

main                                  staging
────                                  ───────
hotfix/issue-123 ──┐
                   │  PR target: main
                   │  (the one exception)
                   ▼
                   │  hotfix.yml runs
                   │  build → test → smoke → publish →
                   │  tag vX.Y.Z → GitHub Release
                   │
                   │  auto-backmerge main → staging
                   │  (carries the fix forward)
                   ▼
              staging is in sync with main.
                   │
                   │  follow-up PR target: staging
                   │  carries a Changeset (patch)
                   ▼
              staging has the audit entry for the fix.

The flow is five steps; the rest of this page walks through each.

Note on the branching model. CLAUDE.md documents the model as main <- staging <- dev, but dev is a conceptual name for the collective per-feature work-in-progress, not a long-lived branch. The model feature/* and fix/* branches target staging directly; there is no dev branch to back-merge into. The back-merge target after a hotfix is therefore staging only. Active feature/* branches pick up the fix on their next rebase.

3. Cut the hotfix branch

Cut the branch from main, never from staging. The branch should be the production code plus nothing else, so what you test is exactly what production will get.

git checkout main
git pull
git checkout -b hotfix/issue-123

If the fix already exists as a commit on staging, cherry-pick it onto the hotfix branch rather than rebuilding it:

git cherry-pick <commit-hash>

If the fix does not exist yet, write it directly on the hotfix branch.

4. Open the hotfix PR against main

The hotfix PR targets main directly. This is the one exception to the rule that every PR targets staging (see the Release Process page for the normal pipeline).

A few rules apply:

  • The PR does not need a Changeset file. The per-PR Changeset rule (Authoring Changesets § 8) applies to PRs targeting staging; hotfix PRs are explicitly out of its scope. The follow-up PR on staging carries the Changeset, see § 7.
  • The PR title should make the urgency obvious, for example [HOTFIX] Fix panic in Result.fold on circular references (#123).
  • The PR description should link the incident or issue, summarize the root cause, and list the tests run.
  • Branch protection on main requires the hotfix PR to be reviewed before merge, but the reviewer pool may be smaller (the hotfix GitHub environment, documented in the Release Process page).

5. Ship the hotfix

When the hotfix PR merges into main, a dedicated hotfix.yml workflow fires (not the regular publish.yml). The workflow:

  • Runs pnpm build and pnpm test against the merge commit.
  • Runs the smoke test on dist/.
  • Runs pnpm changeset publish --tag latest.
  • Tags the merge commit as vX.Y.Z.
  • Creates a GitHub Release page with auto-generated notes.

The smoke test, the anti-republish guard, and the OIDC publish are identical to the regular release path. What differs is the trigger: a push event on main from a hotfix/* branch, instead of a pull_request: closed on a regular PR.

6. Back-merge to staging

After the hotfix is published, main is ahead of staging. Back-merge is mandatory. Skipping it is the usual cause of the next merge conflict.

The back-merge is automated by a workflow that fires on every push to main:

auto-backmerge: main → staging
  • open a PR with title "Backmerge main → staging"
  • skip if there is nothing to backmerge
  • skip if a backmerge PR is already open
  • do not trigger another backmerge attempt on its own merge (anti-recursion)
  • auto-merge on green CI

If the auto-backmerge workflow is not enabled on the repository, the maintainer runs the merge manually:

git checkout staging
git merge main
git push

Active feature/* and fix/* branches pick up the fix on their next rebase from staging. There is no dev branch acting as an intermediate.

7. Open the follow-up PR on staging

The hotfix PR shipped to npm without a Changeset, which means the CHANGELOG.md for that release is empty (or only contains unrelated changes). To restore the audit trail, open a follow-up PR on staging that:

  • Targets staging.
  • Adds a Changeset file under .changeset/ with patch level and a one-line summary describing the hotfix (e.g. Fixed panic in Result.fold on circular references (#123).).
  • Has no code changes. It is a documentation PR.

This follow-up PR follows the normal per-PR Changeset rule and lands in the next regular release, where the user-visible changelog entry finally appears.

Why a separate PR? Because the hotfix itself cannot wait for a Changeset review, and the follow-up PR is too trivial to justify bypassing staging. Splitting them keeps the hotfix fast and the changelog honest.

8. Why the rule above all: every main merge is a release

The Release Process page § 1.1 establishes that every merge to main triggers a release. The hotfix is the only path where that rule produces a release without a corresponding changelog entry on the merge commit itself.

This is intentional. The trade-off is:

  • Hotfix path: minimal time to production. Trade-off: the changelog entry is deferred to the next release via the follow-up PR.
  • Regular path: the changelog entry is on the same commit as the release. Trade-off: the fix waits for staging to be shippable.

Both paths produce a complete, audited release at the end. The hotfix path just defers the visible part of the audit trail by one release.

9. Related documents

Clone this wiki locally