Flutter 3.47 Upgrade Guide: UI Packages, Impeller, and iOS 15

Flutter 3.47 Upgrade Guide: UI Packages, Impeller, and iOS 15 Flutter

The safest way to upgrade to Flutter 3.47 is to separate the SDK upgrade from the optional design-package migration. First move to the latest 3.47 stable hotfix, run your existing tests and platform builds, then evaluate material_ui and cupertino_ui on a dedicated branch. That order makes failures easier to attribute and keeps rollback simple.

Flutter 3.47 is more than a routine framework update. It makes Impeller the default renderer on desktop, raises the supported Apple deployment baselines, graduates Widget Previews to stable, and introduces standalone Material and Cupertino packages as an opt-in migration. This guide turns those changes into a production-minded upgrade plan.

What Changes in Flutter 3.47

Flutter 3.47.0 shipped on August 12, 2026, followed by the 3.47.1 hotfix. The changes that deserve explicit testing are:

  • material_ui and cupertino_ui are available as standalone packages. Moving to them is opt-in in this release.
  • The minimum supported deployment target is now iOS 15 and macOS 12.
  • Apps built with Xcode 27 must use the UIScene lifecycle.
  • Impeller is enabled by default on macOS, Windows, and Linux.
  • Flutter Widget Preview is stable and caches its local build under .widget_preview/.
  • Flutter web continues moving toward Wasm; --wasm remains an explicit build option.
  • The verified Android toolchain matrix now includes Java 17, KGP 2.4.0, AGP 9.1.0, Gradle 9.3.1, and API 36 values.

Not every application needs every migration immediately. A mobile-only app does not need desktop renderer work, and an application can remain on the SDK-bundled Material and Cupertino libraries during the 3.47 cycle. Build a checklist from the platforms and packages you actually ship.

Capture a Baseline Before Upgrading

Create a short-lived upgrade branch and record the toolchain you can currently reproduce:

git switch -c chore/flutter-3-47
flutter --version
flutter doctor -v
flutter pub outdated
flutter analyze
flutter test

Also build the release artifacts that matter to your product. For example:

flutter build appbundle --release
flutter build ipa --release
flutter build web --release
flutter build windows --release

Run only the commands for configured targets. Save representative screenshots, golden-test results, startup timings, frame traces, application size, and a copy of pubspec.lock. If the upgrade introduces a visual or performance regression, these artifacts give you a concrete comparison instead of relying on memory.

Do not combine unrelated dependency upgrades with the SDK move. A clean dependency diff makes it much easier to decide whether a problem comes from Flutter, a plugin, or your own migration.

Upgrade the SDK First

Move to the current stable channel and confirm the exact version rather than assuming that the word “stable” means the expected patch:

flutter channel stable
flutter upgrade
flutter --version
flutter doctor -v
flutter pub get

Next, inspect automated migrations before applying them:

dart fix --dry-run
flutter analyze
flutter test

Fix analyzer errors and reproduce your pre-upgrade release builds before changing design-system imports. When this stage is green, commit it separately. That commit becomes a useful rollback point and proves the core SDK can run your existing application without the optional UI-package migration.

Check the Android Toolchain Deliberately

Flutter 3.47 is verified with Java 17, Kotlin Gradle Plugin 2.4.0, Android Gradle Plugin 9.1.0, and Gradle 9.3.1. The SDK defaults reported for this release are compile and target API 36 with minimum API 24.

Treat that matrix as a compatibility target, not permission to edit every version blindly. Run flutter doctor -v, inspect the Gradle files generated for your project, and check every Android plugin before changing AGP or Gradle. If an older plugin blocks the upgrade, resolve that dependency separately rather than stacking manual Gradle changes until the build happens to pass.

Decide When to Adopt the Standalone UI Packages

Flutter 3.47 still includes the original SDK-bundled Material and Cupertino libraries, so you can upgrade the SDK without immediately changing imports. The standalone packages are most valuable when you want design-system updates on a schedule independent of the quarterly Flutter SDK.

Try the migration only after the SDK-only baseline is healthy:

dart fix --apply --code=migrate_design_widgets
flutter pub get
flutter analyze
flutter test

The migration changes imports such as:

// Before
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

// After
import 'package:material_ui/material_ui.dart';
import 'package:cupertino_ui/cupertino_ui.dart';

If the fix does not update pubspec.yaml, add the packages explicitly and run the migration again:

flutter pub add material_ui
flutter pub add cupertino_ui
dart fix --apply --code=migrate_design_widgets

Applications using Flutter localizations also need to import the new localization classes. A Material application can use the combined delegates exposed by material_ui:

localizationsDelegates: GlobalMaterialLocalizations.delegates,

Third-party dependencies might still import package:flutter/material.dart. The standalone packages include compatibility bridges for mixed widget trees. Use a bridge as a temporary migration tool, verify themes and localizations on every route, and remove it after dependencies adopt the new packages.

Because the design packages can now release independently, review their changelogs and keep versions locked through pubspec.lock in application repositories. An SDK upgrade no longer tells you the complete design-library version by itself.

Test the New Apple Platform Baselines

Flutter 3.47 raises the minimum supported deployment versions from iOS 13 to iOS 15 and from macOS 10.15 to macOS 12. Align the targets in Xcode, CocoaPods configuration, CI images, and any native plugins. Then rebuild from a clean state:

flutter clean
flutter pub get
flutter build ipa --release
flutter build macos --release

When building with Xcode 27, UIKit applications must use the UIScene lifecycle. The Flutter CLI handles the normal generated-project migration, but projects with a custom AppDelegate, add-to-app integration, or older plugins need closer inspection. Test cold launch, deep links, push-notification taps, background-to-foreground transitions, and state restoration on a real device or simulator supported by the new toolchain.

The release also warns that Intel Mac support is winding down. If your CI, release workstation, or macOS test coverage still depends on Intel hardware, document that dependency now and plan an Apple Silicon migration before warnings become hard errors.

Compare Desktop Rendering with Impeller

Impeller is now the default renderer on macOS, Windows, and Linux. Its shader pipeline is designed for predictable frame performance, but a renderer change can expose differences in custom shaders, clipping, text, color, or plugin-backed textures.

Run visual regression tests and exercise animation-heavy screens on every desktop target you ship. Capture a DevTools performance trace for a representative workflow and compare it with the pre-upgrade baseline.

For diagnosis, you can temporarily run with the legacy renderer:

flutter run -d windows --no-enable-impeller
flutter run -d macos --no-enable-impeller
flutter run -d linux --no-enable-impeller

If the problem disappears, reduce it to a small reproduction and report it to the Flutter issue tracker with platform, GPU, screenshots, and a performance trace. Do not treat the opt-out as a long-term architecture decision: Flutter states that desktop fallback options will be removed in a future release.

Add Stable Widget Previews to the UI Workflow

Widget Preview is stable in Flutter 3.47. It renders isolated components without launching the complete application and can be opened from supported IDEs or the command line:

flutter widget-preview start

Annotate a top-level builder, a static method, or a public constructor that has no required arguments:

import 'package:flutter/material.dart';
import 'package:flutter/widget_previews.dart';

@Preview(
  name: 'Compact status card',
  size: Size(360, 160),
  brightness: Brightness.light,
)
Widget compactStatusCardPreview() {
  return const MaterialApp(
    home: Scaffold(
      body: Center(child: Text('Deployment healthy')),
    ),
  );
}

The previewer uses Flutter web, so code that calls dart:io, dart:ffi, or unsupported native plugin APIs cannot execute there. Wrap platform services behind interfaces and provide preview-safe dependencies. Add .widget_preview/ to your repository ignore rules if your tooling does not already exclude it; the directory is a local build cache, not source code.

Use previews to shorten the feedback loop, not to replace widget, golden, integration, accessibility, or device tests. A component that looks correct in the previewer can still fail when navigation, native services, real localization data, or constrained layouts are involved.

Use a Two-Phase Rollout

A low-risk production rollout separates compatibility from optional modernization:

  1. Upgrade to the latest Flutter 3.47 stable hotfix.
  2. Resolve analyzer and build failures without migrating UI packages.
  3. Test Android, Apple, web, and desktop changes relevant to your product.
  4. Ship or stage that SDK-only update.
  5. Migrate to material_ui and cupertino_ui in a second change.
  6. Compare themes, localizations, golden tests, and third-party widget trees.
  7. Keep the pre-upgrade SDK pin and lockfile available for rollback.

Before release, confirm that CI uses the same Flutter patch as developer machines, every configured platform produces a release artifact, Apple deployment targets match the new minimums, and desktop rendering has been visually compared. For web applications, test a normal release build before separately evaluating flutter build web --release --wasm; do not make two rendering migrations indistinguishable in one release.

Conclusion

Flutter 3.47 is worth adopting for its tooling, platform readiness, and desktop rendering improvements, but its most visible change—the standalone design packages—does not need to happen in the same commit. Upgrade and validate the SDK first, then migrate Material and Cupertino imports on a controlled branch. That sequence gives teams the benefits of 3.47 while keeping regressions attributable and rollback practical.

Comment

Copied title and URL