Flutter 3 Migration: Real Pitfalls Moving from 2.x to 3.x
Contents
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 changing2. Create Migration Branch
git checkout -b migration/flutter-3-upgradeUpgrade Steps
Step 1: Update Dart SDK Constraint
# pubspec.yaml
environment:
sdk: '>=2.18.0 <4.0.0' # change to thisStep 2: Update pubspec.yaml Dependencies
# First upgrade Flutter SDK
flutter upgrade
# Update dependencies
flutter pub upgradeThis 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-safety3. iOS CocoaPods Version Requirement
# ios/Podfile
platform :ios, '12.0' # minimum version bumped to 12.0Pitfalls 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 childPit 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.0Post-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 updatePerformance 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:
- Prepare: create branch, backup
- Dependencies: upgrade SDK first, then dependencies
- Breaking changes: Material 3, null safety, go_router
- Testing: build, analyze, tests all run through
- 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.