Flutter 3.47 offers Material as the standalone material_ui package; how do you migrate an app off package:flutter/material.dart, and what can break?
answer
- in-SDK library frozen since 3.44
- opt-in in 3.47, deprecation later
- dart fix migrate_design_widgets
- a compatibility bridge for dependencies
- types in public APIs do not bridge
basics
~10 sRun dart fix --apply --code=migrate_design_widgets and add material_ui (and cupertino_ui if used). Dependencies still importing flutter/material.dart can be bridged with MaterialUiCompatibilityBridge for context lookups, but not where their public APIs expose Material types.
solid answer
~50 sSince Flutter 3.44 the in-SDK `package:flutter/material.dart` and `cupertino.dart` are frozen, and 3.47 is the first release where the standalone `material_ui` and `cupertino_ui` packages can be opted into; the in-SDK libraries are due for formal deprecation later. The 1.0 packages matched the frozen code, and new work, such as Material 3 Expressive, now ships only in the packages under semantic versioning. To migrate I run `dart fix --apply --code=migrate_design_widgets`, which rewrites imports to `package:material_ui/material_ui.dart`, add the dependency with `flutter pub add material_ui` if the fix did not, and run `dart fix` again. The risk is dependencies: one that still imports the old library works under `MaterialUiCompatibilityBridge`, which injects theme and localizations so its `Theme.of` calls resolve, but one whose public API takes or returns a Material type like `ColorScheme` will not type-check until it migrates too.
code
bash · 4 linesdart fix --apply --code=migrate_design_widgets
flutter pub add material_ui
flutter pub add cupertino_ui # only if Cupertino widgets are used
dart fix --applygo deeper
Recall that Material is becoming a separate package, material_ui, and that one dart fix command rewrites the imports.
Explain what is frozen since 3.44, what is opt-in in 3.47, the migration steps, and why widget names stay the same.
Show how you would migrate a real app: inventory dependencies, bridge the context-only ones, block on type-coupled ones, and guard visuals with goldens.
Decide when to migrate given a scheduled deprecation, how to sequence dependency upgrades across teams, and how to adopt a faster-moving design package safely.
## What moved and what is frozen Until recently, Flutter's Material widgets lived inside the SDK as `package:flutter/material.dart`, released with the framework. The design libraries are now being **decoupled**: - contributions to the in-SDK `material.dart` and `cupertino.dart` were **frozen from Flutter 3.44**; - starting with **3.47**, version 1.0 of **`material_ui`** and **`cupertino_ui`** is on pub.dev, and apps can opt in; - the 1.0 versions **match the frozen framework code**, so switching changes no visuals by itself; - later releases follow **semantic versioning** and are planned to ship more often than the SDK; - the in-SDK libraries are **scheduled for formal deprecation** in an upcoming stable release, so migrating is optional today but expected. The pinned `material_ui` in this toolchain is 1.5.0: it requires Dart `^3.13.0` and Flutter `>=3.47.0`, and depends on `cupertino_ui`. Its changelog shows new work landing only in the package, such as a `StyleVariant` enum for Material 3 Expressive (1.2.0) and Expressive support for `IconButton` (1.5.0). ## Migrating an app 1. Run `dart fix --apply --code=migrate_design_widgets`. It rewrites imports from `package:flutter/material.dart` and `package:flutter/cupertino.dart` to `package:material_ui/material_ui.dart` and `package:cupertino_ui/cupertino_ui.dart`. 2. If the fix did not add them, run `flutter pub add material_ui` (and `flutter pub add cupertino_ui` if Cupertino widgets are used). 3. Run `dart fix` once more for follow-on fixes such as import ordering, then the analyzer and the test suite. 4. Review golden tests: 1.0 matches the frozen code, but upgrading the package later can change visuals, which is the point of its faster release cycle. The widget names do not change: `MaterialApp`, `Scaffold`, `FilledButton` and `NavigationBar` are used as before, now from the new import. `ThemeData.useMaterial3` still defaults to `true` in the package. ## Dependencies that have not migrated The hard part is third-party packages. A package that still imports `package:flutter/material.dart` sees the **old** library's classes, which are different Dart types from those in `material_ui`, even when the names match. | Dependency's coupling | Example | What works | |---|---|---| | reads design state from context | calls `Theme.of(context)` or `MaterialLocalizations.of(context)` | works under `MaterialUiCompatibilityBridge` | | exposes Material types in its API | takes a `ColorScheme`, returns a `TextTheme`, accepts a `FloatingActionButtonLocation` | does not type-check; the dependency must migrate | | already migrated | for example go_router 18.0.0 | works directly | `MaterialUiCompatibilityBridge` is a widget, typically placed in `MaterialApp.builder` or around a legacy subtree, that injects theme and localization data for the old library, so unmigrated widgets below it read a theme and labels. It cannot convert types: a `ColorScheme` from `material_ui` cannot be passed where the dependency expects the SDK's `ColorScheme`, because Dart's static types differ across the two imports. ## Planning the change on a real app - Inventory dependencies that import Material or Cupertino, and sort them into the three rows above. - Upgrade those with migrated releases first; go_router 18.0.0, for example, requires Flutter 3.44 and Dart 3.12 and already uses the new packages. - Migrate the app in one change, add the bridge for context-only dependencies, and keep a list of type-coupled ones as blockers. - Pin `material_ui` with a caret constraint and treat minor upgrades like any UI dependency: read the changelog and re-run goldens. ## What this means in an interview A strong answer separates three states that are easy to blur: 1. **Today, on 3.47**: both the in-SDK library and `material_ui` work; the SDK one is frozen, so it gets no fixes or new components. 2. **Migrating**: imports change, widget names do not, and dependencies decide how smooth it is. 3. **Later**: the in-SDK libraries will be formally deprecated in a future stable release, so new projects and active apps should plan the move rather than wait for warnings. It also helps to know what did not change: `ThemeData`, `ColorScheme.fromSeed`, the component themes and every widget covered by Material 3 work the same after the switch; only their import and their release cycle moved.
- Why can the compatibility bridge not fix a dependency that takes a ColorScheme parameter?Because the SDK's `ColorScheme` and `material_ui`'s `ColorScheme` are two different classes that happen to share a name. Dart checks types statically across imports, so a value of one cannot be passed where the other is expected. The bridge only injects inherited data that widgets look up through context; it cannot change a function's parameter type. That dependency has to release a migrated version.
- Is there any visual change on day one of the migration?Not from the switch itself: the 1.0 packages were cut to match the frozen framework code. Visual changes arrive when the package is upgraded, for example new Material 3 Expressive work that lands only in `material_ui`. Treat package upgrades like any UI dependency bump: read the changelog and re-run golden tests.
saying these in an interview costs you the question
- package:flutter/material.dart was removed in Flutter 3.47.
- Adding material_ui to pubspec.yaml switches all imports automatically.
- MaterialUiCompatibilityBridge makes every unmigrated dependency compile.
- The in-SDK Material library still receives new components each release.
- Migrating to material_ui renames Scaffold and the other widgets.