English for Writing a Migration Guide Between Major Versions
Learn the English structure and phrasing for writing a clear upgrade guide that walks users through breaking changes step by step.
A migration guide is read under a specific kind of stress: the reader already has working code, and they’re trying to upgrade without breaking it. The English needs to be ordered, specific, and honest about what will and won’t work automatically. This guide covers the structure and phrasing that makes an upgrade guide genuinely usable.
Key Vocabulary
Breaking change — a change that requires the reader to modify their existing code for it to keep working after the upgrade, as opposed to a change that’s automatically compatible.
“This is a breaking change: the onError callback now receives an Error object instead of a string, so any code that assumes a string will need to be updated.”
Codemod — an automated script that rewrites code to match a new API, reducing the manual work needed for a migration.
“We’ve published a codemod that handles most of this rewrite automatically — run npx migrate-tool v3 before making any manual changes, since it’ll handle the mechanical parts.”
Before/after example — a paired code snippet showing the old pattern and the new pattern side by side, which is the single most effective format for a migration guide.
“Before: client.fetch(url, callback). After: const result = await client.fetch(url). The callback-based API has been removed entirely in favor of promises.”
Migration path — the sequence of steps or intermediate versions a user needs to go through to reach the target version, especially relevant when you can’t jump directly from an old version to a new one. “There’s no direct migration path from v2 to v4 — you’ll need to upgrade to v3 first, run its migration guide, and then upgrade to v4 separately.”
Deprecation window — the period during which an old API still works but emits a warning, giving users time to migrate before the old API is removed entirely.
“The old Client class still works in v3 but is deprecated and logs a console warning. It will be removed entirely in v4, so now is the time to migrate.”
Common Phrases
- “Before: [old code]. After: [new code].”
- “This is a breaking change: [what changed] means [what you need to update].”
- “Run the codemod first: [command]. It handles [X] automatically; you’ll need to manually update [Y].”
- “There is no direct migration path from [old version] to [new version] — upgrade via [intermediate version] first.”
- “Estimated migration time: [X], depending on how much of your codebase uses [affected API].”
Example Sentences
Opening a migration guide with a scope summary:
“This guide covers migrating from v2.x to v3.0. The main breaking changes are: the removal of the callback-based API in favor of promises, a new required apiVersion field in the client config, and the renaming of fetchAll to list. Most projects can complete this migration in under an hour.”
Writing a before/after pair with an explanation of why it changed: *“Before:
client.fetch(url, (err, data) => { ... });
After:
try {
const data = await client.fetch(url);
} catch (err) { ... }
The callback API has been removed in favor of promises, which better supports the async/await patterns most consumers were already using via a wrapper.”*
Being explicit about what a codemod does and doesn’t handle:
“The codemod (npx migrate-tool v3) automatically rewrites callback-based calls to use async/await. It does not rewrite custom error-handling logic that branches on the old string-based error codes — you’ll need to update those manually, and we’ve flagged each occurrence with a // TODO(migrate) comment for you to find them.”
Warning about a subtle behavioral change, not just a syntax change:
“Note: this isn’t just a syntax change. In v2, list() returned results in insertion order. In v3, list() returns results ordered by updatedAt by default. If your code depends on insertion order, pass { sort: 'created' } explicitly to preserve the old behavior.”
Professional Tips
- Structure every breaking change as a before/after code pair, not a prose description alone — code is unambiguous in a way that a sentence describing code often isn’t.
- State explicitly what a codemod handles and what it doesn’t — an incomplete mental model of automation scope causes people to either skip necessary manual work or redo work the codemod already did.
- Distinguish syntax changes from behavioral changes — a rename is low-risk, but a change in default behavior (like sort order) can cause silent bugs that don’t show up as errors, and deserves extra emphasis.
- If there’s no direct migration path between two versions, say so at the very top of the guide — discovering this halfway through an upgrade is far more frustrating than being told up front.
- Give a rough time estimate for the migration, even an approximate one — it helps readers plan the work and signals you’ve thought about their experience, not just documented the changes.
Practice Exercise
- Write a scope summary for a hypothetical major version migration guide, listing the main breaking changes.
- Write a before/after code pair with a one-sentence explanation of why the change was made.
- Write a warning note distinguishing a syntax change from a behavioral change in a migration.