Every mature Ember app we look at owns addons. Not just the ones from npm — the in-repo addon someone added in 2016 to share a few components, a private component library published to a company registry, a fork of an abandoned addon with two patches in it. These packages are usually the last thing anyone touches, and they are the thing most likely to hold up an Embroider or Vite migration.
The v2 addon format (RFC 507) is what fixes that. A v1 addon is a build-time participant: it hooks into the host app's broccoli pipeline, can rewrite trees, inject code, and relies on the app's resolver to find its files. A v2 addon is just an npm package of plain JavaScript and templates with an ember-addon section in package.json describing what it contributes. No build hooks. A bundler can read it directly.
That difference is the whole point. Static builds get faster and smaller the fewer v1 addons remain in the graph, and the addons you own are the ones you can actually convert.
Start with an inventory, not a conversion
List every addon in the dependency graph and mark three things for each: v1 or v2, do we own it, and does the app actually use it.
The ownership column matters more than the format column. For third-party v1 addons your options are upgrade, replace, or live with the compatibility layer — covered in our post on auditing and replacing abandoned addons. For addons you own, conversion is on the table, and you can sequence it.
The usage column earns its keep immediately. In-repo addons are frequently half-dead: a package that exports twelve components of which three are still invoked. Deleting a dead in-repo addon is a faster win than porting it, and it is a one-afternoon PR. Do that pass first.
Flatten what does not need to be a package
Many in-repo addons exist for reasons that no longer apply. They were created to get a set of components out of the app tree, to share code with a sibling app that was later retired, or because the team was told that was the tidy way to do it.
If an in-repo addon is consumed by exactly one app and has no build-time behavior, the cheapest correct move is to move its files into the app and delete the package. You lose nothing — there was no reuse — and you remove a v1 addon from the graph without writing a v2 addon at all. In a codebase with six in-repo addons, it is common for three or four to resolve this way.
Keep the package only when it is genuinely shared across apps, published for other teams, or has a real reason to version independently.
Port the survivors with the blueprint
For the addons that stay, do not hand-edit the old package into shape. Generate a new one with @embroider/addon-blueprint and move code into it. The blueprint gives you the layout that works: a src/ directory of authored files, a Rollup config using @embroider/addon-dev, the app-reexports plugin for anything that must still appear in the host app's namespace, and a separate test-app package that consumes the addon the way a real app does.
The mechanical parts, in the order they tend to bite:
Explicit imports. In a v1 addon, one file could reference another through the app's module namespace. In v2 there is no resolver magic across the package boundary; a component that uses a utility imports it by relative path. This is mostly find-and-replace, and it surfaces genuine cycles that the resolver had been hiding.
Templates. Co-located .hbs files work, but the template tag (.gjs/.gts) is where this format is heading, and an addon is a low-risk place to try it — the blast radius is one package. If your app already has the template tag set up, port the addon's components to it while you are in there.
Declared dependencies. A v1 addon could rely on the host app happening to have something installed. A v2 addon must declare it, as a dependency or a peer dependency. Expect to find two or three undeclared uses of ember-data, a date library, or an icon set. Those were latent breakages.
The app/ re-export directory. If consumers import from my-addon/components/thing or rely on the component being resolvable by name in templates, addon-dev's app-reexports keeps that working during the transition. Configure it deliberately and write down which exports are public; this is the moment to decide what the package's API actually is, which nobody has done since it was created.
Build-time behavior. If the old addon did real work in index.js — a custom preprocessor, injecting config, generating files — that does not port. It has to move somewhere: a real build plugin, a codegen step, or plain runtime configuration. This is the only category that can turn a two-day conversion into a two-week one, so identify it during the inventory rather than discovering it mid-port.
Keep the app shippable while you do it
Convert one package per pull request, and keep the app's consumption of it unchanged in that PR. Because a v2 addon is a normal package, a v1 and a v2 addon can coexist in the same dependency graph indefinitely; there is no coordinated cutover. Point the app at the converted package, run the suite, ship.
The test-app pattern is worth the extra directory. Addon tests that run inside the host app's suite drift into depending on host app setup, which is how a shared package quietly becomes unshareable. A test app that consumes the addon from outside catches missing exports and undeclared dependencies before your consumers do.
What it is worth
Be honest about the payoff. Converting addons you own does not by itself make the app faster — it removes obstacles. The concrete gains are that Embroider's static flags become achievable, Vite's dev server can serve your own code without a compatibility shim, rebuilds get quicker in the packages you edit most, and new hires read a normal npm package instead of a broccoli hook.
If you are not heading toward a static build, and your in-repo addons are stable and nobody is blocked, this work can wait. It is a prerequisite, not an improvement. The time to do it is when an Embroider or Vite migration is on the plan for the next quarter or two — and the time to do the inventory and the deletions is now, because that part shortens the list either way.
If you want a second opinion on which of your packages should be converted, flattened, or deleted, an Ember app assessment produces exactly that list with effort ranges. Get in touch with your Ember version and a rough count of addons you own.