Ember's LTS lines exist so that apps can upgrade on a schedule instead of in a panic. Yet the most common state we find in assessments is an app parked two or three LTS lines back, with a story about the upgrade branch that got abandoned. The branch always fails for the same reason: it tried to do everything at once. Here is the playbook that gets a parked app moving again — and keeps it current afterwards for a few days per cycle instead of a quarter of heroics.
The core rule: deprecations first, then bump
An Ember version bump on a clean app is boring. What makes upgrades explode is attempting the bump while hundreds of deprecation warnings are outstanding, because each warning is a place the next major version will simply break.
So invert the order. On your current version, install ember-cli-deprecation-workflow and generate the workflow config. It converts the wall of console noise into an explicit inventory: every deprecation ID your app triggers, each one silenced until you're ready to work it. Then burn the list down deprecation by deprecation, as ordinary PRs on your ordinary release train, flipping each ID to throw as you clear it so it can never come back. When the config file is empty and everything throws, the major-version bump becomes a small change instead of an event.
Move LTS to LTS, one line at a time
Don't hop from 3.28 to the newest release in one jump. Walk the LTS lines in order — each LTS is a supported, documented resting point, and the deprecation tooling assumes you're using them that way: each line deprecates what the next major removes. The rhythm per line is always the same: bump with ember-cli-update, resolve its merge conflicts (it applies the blueprint diff rather than regenerating your app), get the suite green, clear the new deprecations to throw, ship it, soak it in production for a week or two, repeat. Every step is on main and releasable; there is no long-lived branch anywhere in this process.
The blockers worth knowing in advance
Addons, always addons. Before each hop, check your dependency list against the target version — ember-observer status, repository activity, and whether a maintained successor exists. An abandoned addon that hard-depends on removed APIs is the single most common reason a hop stalls. Decide its fate (upgrade, replace, vendor, delete) before the bump, not in the middle of it.
jQuery removal. Apps that grew up before 3.x often lean on jQuery through this.$() and through addons. Clearing the jQuery deprecations is sometimes a mini-project of its own; treat it as one, with its own PRs, rather than a footnote of a version hop.
Ember Data's evolution. The store's public API has been steadily reshaped across the 4.x and 5.x eras. If your app has custom adapters and serializers from the 2.x days, budget separately for that modernization work — it's the second most common stall point after addons, and pretending it's part of "just the upgrade" is how estimates go wrong.
Test infrastructure. Old apps carry old testing idioms (moduleFor-style tests, jQuery-based test helpers). The suite is your safety net for everything else in this playbook, so bringing tests to current idioms is worth doing early, and there are codemods covering most of the distance.
Keep a decision log
Every deprecation cleared, addon replaced, and API migrated should leave a one-paragraph record: what changed, why, what to watch. On an app whose original authors are gone, this log is how the next upgrade avoids re-deriving everything — and it's the cheapest knowledge transfer you'll ever buy.
Staying current once you've caught up
The steady state is a calendar rule: when a new LTS lands, schedule the hop within the quarter. The deprecation workflow file stays empty-and-throwing between hops, ember-cli-update does the mechanical part, and each hop is a few days of normal engineering. Teams are consistently surprised that this is all it takes — but that's the actual product Ember's release discipline is selling. The framework holds up its end; the playbook is just about holding up yours.
If you're more than three lines behind
Get an assessment before committing to the walk. Somewhere around the third parked LTS line, the accumulated addon decay and API drift can make "upgrade in place" cost comparable to more strategic options, and it's worth knowing the effort range for each path before spending a quarter on the first one. That's a numbers question, not a loyalty question — and it deserves a numbers answer.