Run every deterministic @backstage/* MUI 4 → BUI codemod from the Codemod Registry in a single ordered pass.
This recipe is not tied to a single Backstage release. It is the orchestration package for the ongoing MUI 4 to BUI migration work in app and plugin repositories.
Recommended order
Bootstrap first — @backstage/migrate-mui-bootstrap-to-bui adds @backstage/ui / @remixicon/react dependencies and the global BUI stylesheet.
Transforms — icons, styles, core components, complex components, form controls, then layout, in the stable sequence below.
Cleanup last — @backstage/remove-mui-dependencies drops unused @material-ui/* packages from package.json only after source files no longer import them.
Do not run remove-mui-dependencies before the component transforms finish, or packages that still have MUI imports may be removed incorrectly.
@backstage/migrate-mui-layout-to-bui-layout never maps Paper to Surface. Bare Paper → Box bg="neutral"plus a verify TODO that MUI’s default elevation chrome was dropped; card-like Paper → Card; explicit elevation / variant / ambiguous Paper → left with TODO(backstage-codemod).
Button outlined → secondary
@backstage/migrate-mui-button-to-bui-button maps variant="outlined" → variant="secondary" silently (BUI secondary is the outlined visual). The transform emits metric outlined-to-secondary so operators can quantify remaps in dry-run output.
Density (size defaults)
BUI controls default to size="small" while MUI defaults to medium. These packages emit size="medium" when MUI omitted size (or used medium/large), and preserve explicit size="small":
Button / ButtonIcon / Tag
TextField family (TextField prop first; else parent FormControl size)
Most transforms use migrate-mui-<source>-to-bui-<target>. A few intentionally omit -bui- in the target segment when the BUI export name is the product surface (not a “BUI-prefixed” alias):
Package
Why the name looks different
@backstage/migrate-mui-typography-to-text
Target is BUI Text
@backstage/migrate-mui-chip-to-tag
Target is BUI Tag
@backstage/migrate-mui-icon-button-to-button-icon
Target is BUI ButtonIcon
@backstage/migrate-mui-icons-to-remix-icons
Target is @remixicon/react, not @backstage/ui
@backstage/migrate-mui-radio-checkbox-to-bui
Covers radio/checkbox groups → BUI groups
Usage
bash
# Dry-run first (published registry packages)
yarn dlx codemod@latest run @backstage/mui4-to-bui-migration-recipe \
--target /path/to/backstage-app \
--dry-run
# Apply
yarn dlx codemod@latest run @backstage/mui4-to-bui-migration-recipe \
--target /path/to/backstage-app
Local pre-publish dry-runs (workflow.local.yaml)
Before packages are published, use the sibling-path workflow to exercise unpublished transforms against a local Backstage checkout (commonly ../backstage from the monorepo root):
bash
cd codemods/misc/mui4-to-bui-migration-recipe
# Validate registry + local workflows (also: yarn test)
bash scripts/validate-workflows.sh
# Dry-run against a sibling Backstage tree (run from this package directory).
# Pass the workflow *file* path so the CLI does not rewrite to workflow.yaml.
yarn exec codemod workflow run -w ./workflow.local.yaml \
-t /absolute/path/to/backstage \
--dry-run --no-interactive --allow-dirty
workflow.local.yaml is a maintainer-only mirror (not the published default). It uses the same step order as workflow.yaml, with relative sibling sources (source: '../migrate-mui-…'). Published consumers should keep using the registry recipe.
A full dry-run against the Backstage monorepo (pre-merge hardening) completed cleanly: no Surface emissions; bare Paper sites emit default-elevation verify TODOs; Button reports outlined-to-secondary; Link skips only packages/core-components paths and migrates direct MUI Link elsewhere.
Recipe behavior
Every step runs at default deterministic settings.
The recipe ships noaiFixup parameter.
Ambiguous cases are marked with TODO(backstage-codemod) in the transformed source rather than embedded AI workflow nodes.
Manual follow-up
After the recipe finishes:
Search the repo for TODO(backstage-codemod) and resolve each marker.
Search for remaining Material UI imports, for example:
@material-ui/
@mui/
Re-run typecheck / tests for the packages you migrated.
Spot-check visual polish (spacing, dark mode, token usage) — the recipe does not aim for perfect theme parity.
Out of scope
The following are not covered by this recipe (document-only / manual):
Badge overlays (no safe 1:1 BUI mapping)
CircularProgress / LinearProgress (do not auto-map to Skeleton)
Drawer, Snackbar, Stepper, and Timeline
@material-table/core / material-table and broader table-system migrations
Perfect theme parity, dark-mode polish, and final design-token tuning after the source-level migration
Custom wrapper abstractions that hide MUI components behind project-specific APIs
Notes
workflow.yaml resolves each step from the Codemod registry (source: '@backstage/<package>'), so underlying packages must be published before the recipe can run end-to-end.
Use workflow.local.yaml for pre-publish dry-runs against sibling packages and a local ../backstage tree.
This recipe is orchestration only — it has no transform script of its own. Running yarn test validates the workflow schema via codemod workflow validate.
Ready to evolve your codebase?
Build tailored, compiler-aware skills to assess, plan, and automate complex codebase changes.