Contents

Flutter 3 Migration: Real Pitfalls Moving from 2.x to 3.x

Bottom Line First

Flutter 3 upgrade went smoother than expected, but a few breaking changes need serious attention.

Total time: Medium Flutter project with 100k LOC, 2 person-days for migration.

Pre-Migration Prep

1. Check Current Version

# Check version
flutter --version
# Flutter 2.10.5 • channel stable • Dart 2.16.8

# Check pubspec.yaml
name: my_app
environment:
  sdk: '>=2.16.0 <3.0.0'  # this needs changing

2. Create Migration Branch

git checkout -b migration/flutter-3-upgrade

Upgrade Steps

Step 1: Update Dart SDK Constraint

# pubspec.yaml
environment:
  sdk: '>=2.18.0 <4.0.0'  # change to this

Step 2: Update pubspec.yaml Dependencies

# First upgrade Flutter SDK
flutter upgrade

# Update dependencies
flutter pub upgrade

This step most likely to encounter version conflicts.

Step 3: Handle Breaking Changes

Flutter 3’s main breaking changes:

1. Material 3 Becomes Default

// Flutter 2.x: Material 2 default
// Flutter 3: Material 3 default

// If you want to keep Material 2, must specify explicitly
MaterialApp(
  theme: ThemeData(
    useMaterial3: false,  // add this
  )
)

2. Null Safety Fully Enabled

// Flutter 2.x: null safety already present, but some packages haven't updated
// Flutter 3: all dependencies must support null safety

// Check
flutter pub outdated --null-safety

3. iOS CocoaPods Version Requirement

# ios/Podfile
platform :ios, '12.0'  # minimum version bumped to 12.0

Pitfalls Encountered

Pit 1: provider 5.0 Breaking Change

// Flutter 2.x
ChangeNotifierProvider(
  create: (_) => MyNotifier(),
  child: ...
)

// Flutter 3
// syntax changed
ChangeNotifierProvider(
  create: (context) => MyNotifier(),  // context parameter required
  child: ...
)

Fix:

// Change all to
ChangeNotifierProvider(
  create: (context) => MyNotifier(),
  child: MyWidget(),
)

// And move Consumer inside child

Pit 2: go_router 6.0 Breaking Change

// Flutter 2.x (go_router 5.x)
GoRoute(
  path: '/home',
  builder: (context, state) => HomePage(),
)

// Flutter 3 (go_router 6.x)
GoRoute(
  path: '/home',
  builder: (context, state) => HomePage(),
  // syntax unchanged, but parameter types changed
)

Real fix: mainly state.extra type changed from dynamic to concrete type.

Pit 3: Network Image

// Flutter 2.x
NetworkImage(url)

// Flutter 3
// NetworkImage unchanged, but cache behavior changed
// If using cached_network_image, need to update version
cached_network_image: ^3.3.0

Post-Migration Checklist

# 1. Build check
flutter build apk --debug
flutter build ios --simulator --no-codesign

# 2. Null safety check
dart analyze --fatal-infos

# 3. Test check
flutter test

# 4. iOS CocoaPods check
cd ios && pod install && pod update

Performance Changes

Post-migration performance (comparison):

Operation Flutter 2.10 Flutter 3.16
Debug build 45s 38s
Release build 180s 160s
APK size 22MB 20MB
Memory usage baseline -8%

Material 3’s memory optimization is real.

Conclusion

Flutter 3 upgrade:

  1. Prepare: create branch, backup
  2. Dependencies: upgrade SDK first, then dependencies
  3. Breaking changes: Material 3, null safety, go_router
  4. Testing: build, analyze, tests all run through
  5. Pitfalls: provider 5.0, go_router 6.0, cached_network_image

Recommendation: Don’t skip minor versions. Upgrade to an LTS version first, confirm OK, then upgrade to major version.