Documenting Breaking API Changes in Release Notes
Best practices for communicating breaking API changes in release notes. Includes before/after examples, migration paths, and deprecation timelines.
Detailed Explanation
Documenting Breaking Changes
Breaking changes are the most important part of any release notes because they directly affect users' ability to upgrade. Poor documentation of breaking changes leads to frustrated users, support tickets, and delayed adoption.
The Breaking Change Anatomy
Every breaking change entry should include:
- What changed — the specific API, config, or behavior
- Why it changed — the motivation (performance, security, consistency)
- How to migrate — concrete steps or code changes needed
- Before and after — code snippets showing the old and new way
Example
### BREAKING CHANGES
> **`authenticate()` now returns a Promise instead of a callback.**
>
> Before (v1.x):
> ```js
> client.authenticate(token, (err, user) => {
> if (err) throw err;
> console.log(user);
> });
> ```
>
> After (v2.0):
> ```js
> const user = await client.authenticate(token);
> console.log(user);
> ```
>
> **Migration:** Replace callback-based calls with async/await. If you
> need callback compatibility, wrap with `util.callbackify()`.
Grouping Strategy
For releases with many breaking changes, group them by area:
- API Changes — function signatures, return types
- Configuration — config file format, env variables
- Behavior — default values, error handling
- Dependencies — minimum versions, removed peer deps
Deprecation-First Approach
Ideally, breaking changes were deprecated first in a previous minor release. Reference that deprecation in the breaking change note so users who followed deprecation warnings are already prepared.
Use Case
Releasing a new major version of a public API, SDK, or framework where backward-incompatible changes require users to update their integration code.