How to announce breaking changes (without losing users)
Every product that lives long enough breaks something on purpose: an API field renamed, a default flipped, an old auth scheme retired. Users forgive breakage — what they don't forgive is surprise. This guide is the playbook for the announcement itself: timing, contents, tone, and where to put it so the people affected actually see it.
The one rule
Nobody affected should learn about the change from the breakage. Every other rule below is a corollary of this one. If a request starts failing, a build stops passing, or a button moves, and the first explanation a user finds is a stack trace — you've spent trust you didn't need to spend, even if the change itself was right.
When to announce: three moments, not one
A breaking change is announced three times:
- At deprecation — the moment you decide the old behavior will die. Say what's deprecated, what replaces it, and the date it stops working. This post starts the clock; without a date it's a vague threat, not a deprecation.
- Before the cutoff — a reminder at a useful interval (a week for small things, a month for APIs other people's code depends on). Repeat the migration path; most readers missed the first post.
- At the change — the day it lands. Short: "as announced on [date], X is now Y. If you see [symptom], do [fix]." This is the post people find from a search when something breaks — write it for that reader.
How much lead time? A default answer that rarely embarrasses anyone: as long as it would take a busy user to migrate, times three. Renamed response field: two weeks. Retired auth scheme: a quarter. If you honestly can't give notice (security), say so — "we removed this immediately because it was exploitable" is an acceptable reason; "we forgot to post" is not. (Security-driven changes have their own comms rules — see security advisories vs changelog.)
Anatomy of the announcement
Five parts, in order. Skipping any of them generates a support ticket:
- "Breaking:" in the title. Front-loaded, unmissable, searchable. "Breaking: API tokens now expire after 90 days" — a reader who scans only titles still gets the message.
- Who is affected — and, just as useful, who isn't. "Only affects you if
you call
/v1/export" lets 90% of readers relax after one sentence. - What the failure looks like. The exact error message, status code, or symptom. This is what makes the post findable by the person debugging at 2am — quote the error text verbatim so search engines can match it.
- The migration, as steps. Before/after code or settings, not a link to a 50-page reference. If migration is one line, show the line.
- The why, in one honest sentence. "The old endpoint couldn't paginate and timed out on large accounts." Users accept almost any change with a real reason attached; "to serve you better" is not a reason.
A template you can steal
Breaking: [old thing] is replaced by [new thing] on [date] Who's affected: [specific trigger — endpoint, feature, setting]. If you don't [use X], you can ignore this. What you'll see after [date]: [exact error / behavior]. To migrate: Before: [old call / setting] After: [new call / setting] Why: [one honest sentence]. Questions → [contact/issue link].
Deprecation timelines that respect users
- Dates, not versions. "Removed in 4.0" means nothing to someone who doesn't track your roadmap. "Stops working on 2026-10-01" is unambiguous.
- Warn in-band if you can. A
Deprecationheader, a console warning, a banner in the UI — the announcement travels with the thing being deprecated, and reaches users who never read changelogs. (API changelogs covers the RFC 8594 headers.) - Don't move the date earlier. Extending a deadline is a kindness; shortening one is a betrayal. If you must, treat it as a brand-new announcement with its own notice period.
- Keep the announcements up. The deprecation post is documentation now. People will land on it from error-message searches for years; make sure the permalink survives.
Better yet, decide your windows and channels once, in writing, before you need them: that's a deprecation policy, and it turns every future announcement into fill-in-the-blanks.
Where to put it
The changelog is the spine: it's dated, permanent, and linkable — the deprecation post, the reminder, and the change-day post all live there, and each links to the others. Then mirror, don't fragment: push the same post to your Discord/Slack, your feed, your status page if the change can page someone. One canonical URL, many mirrors, so "did we announce this?" always has one answer. (This split is covered more in changelog vs release notes.)
Where Wakelog fits
Wakelog is built for exactly this workflow: posts are dated, permalinked, and taggable; scheduled publishing lets you write the change-day post at deprecation time and have it go live at the cutoff automatically; and per-project Discord/Slack/webhook notifications mirror every published post so the announcement reaches people where they already are. Your announcement, its reminder, and the final notice can all be drafted in one sitting — then the timeline runs itself.
Start a changelog — free Next: how to write a changelog →
Related guides
- How to write a deprecation policy (with template)
Decide how you retire things before the fight starts: scope, notice windows, channels, and what “deprecated” actually means — with a copy-paste policy template. - Framework and runtime release notes: shipping a version an ecosystem has to absorb
When you ship a framework or runtime major, almost nobody can upgrade the day you announce it — apps are stuck until the libraries they depend on move first. Your release notes get read twice, by two different audiences, months apart. How to write for adoption in dependency order: RC notes for library authors, GA notes for app developers, codemods, readiness tables, and the one rule about renaming. - Webhook and event payload changes: announcing new shapes to consumers who can’t pin a version
An API consumer chooses when to call you, which version to ask for, and when to upgrade. A webhook consumer wrote a handler during integration week three years ago and hasn’t looked at it since — and whatever your producer sends tonight is what that handler receives, ready or not. Changing a payload you push needs different disciplines than changing an endpoint people call, starting with the fact that you — uniquely — hold a complete list of everyone who will break.
Last updated 2026-07-28 · All guides