Flutter 2.0 Migration Guide for Existing Apps

If you have been running a Flutter application built on the original framework, migrating to Flutter 2.0 is one of the most impactful upgrades you can make in early 2022. With sound null safety, improved web support, and a refined widget catalogue, Flutter 2.0 delivers meaningful gains across stability, performance, and developer experience.

At eawesome, we have migrated several production apps through this process. This guide distils the practical lessons we have learned into a clear, repeatable workflow.

Why Migrate Now

Flutter 2.0 is not simply an incremental version bump. It represents a structural shift in how the framework handles types, rendering, and platform targets. The headline features include:

  • Sound null safety that catches entire categories of runtime errors at compile time
  • Improved rendering engine with better performance on both iOS and Android
  • Web support promotion to stable, opening new deployment targets
  • Desktop support in beta for Windows, macOS, and Linux
  • New widget behaviours including updated Material Design components

Delaying the migration means accumulating technical debt. Many packages in the pub.dev ecosystem have already moved to null-safe versions, and older non-null-safe dependencies will increasingly become blockers.

Pre-Migration Checklist

Befor

e writing a single line of migration code, work through this checklist.

1. Audit Your Dependencies

Run a full dependency audit to understand your exposure:

flutter pub outdated --mode=null-safety

This command shows which of your dependencies have null-safe versions available. If a critical dependency lacks null-safe support, you have three options: find an alternative package, fork and migrate it yourself, or use the // @dart=2.9 escape hatch temporarily.

2. Ensure Test Coverage

Migration is the worst time to discover you have no tests. Before starting, ensure you have reasonable coverage across:

  • Unit tests for business logic
  • Widget tests for UI components
  • Integration tests for critical user flows

If your test coverage is thin, invest time in writing tests before migrating. The migration will change type signatures throughout your codebase, and tests are your safety net.

3. Version Control Hygiene

Create a dedicated migration branch. Commit frequently. The migration can touch hundreds of files, and you want the ability to roll back cleanly if something goes sideways.

git checkout -b migration/flutter-2-null-safety

4. Update Flutter SDK

Ensure you are on the latest stable channel:

flutter channel stable
flutter upgrade
flutter --version

Confirm you are running Flutter 2.x before proceeding.

Step-by-Step Migration Process

S

Step-by-Step Migration Process Infographic tep 1: Migrate Dependencies First

Update your pubspec.yaml to use null-safe versions of all dependencies. Start from the bottom of the dependency graph and work upward.

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0
  http: ^0.13.0
  shared_preferences: ^2.0.0
  intl: ^0.17.0

Run flutter pub get after updating. Resolve any version conflicts before moving forward.

Step 2: Run the Migration Tool

Flutter provides a built-in migration tool that analyses your code and suggests null safety changes:

dart migrate

This launches an interactive web-based tool that shows proposed changes across your codebase. Review each suggestion carefully. The tool is good but not perfect. It tends to be overly conservative, marking more types as nullable than necessary.

Step 3: Manual Review and Refinement

After applying the migration tool’s suggestions, manually review the results. Common patterns to watch for:

Late Initialisation

The migration tool often converts fields to nullable when they are actually always initialised before use. In these cases, late is more appropriate:

// Migration tool suggests:
String? _userName;

// Better approach when you know it will be initialised:
late String _userName;

Use late judiciously. It moves the null check from compile time to runtime, so only use it when you are confident the variable will be initialised before access.

Required Named Parameters

Flutter 2.0 introduces the required keyword to replace the @required annotation:

// Before
MyWidget({@required String title}) : _title = title;

// After
MyWidget({required String title}) : _title = title;

Null-Aware Operators

Lean into Dart’s null-aware operators for cleaner code:

// Instead of explicit null checks:
if (user != null) {
  return user.name;
}

// Use null-aware operators:
return user?.name ?? 'Unknown';

Step 4: Update Widget Code

Several widgets have changed behaviour in Flutter 2.0. Key changes to address:

ElevatedButton, TextButton, OutlinedButton

The old RaisedButton, FlatButton, and OutlineButton are deprecated:

// Before
RaisedButton(
  onPressed: _submit,
  child: Text('Submit'),
)

// After
ElevatedButton(
  onPressed: _submit,
  child: Text('Submit'),
)

ButtonStyle

The new buttons use ButtonStyle instead of individual properties:

ElevatedButton(
  style: ElevatedButton.styleFrom(
    primary: Colors.blue,
    onPrimary: Colors.white,
    padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
  ),
  onPressed: _submit,
  child: Text('Submit'),
)

AppBar Changes

AppBar now uses foregroundColor and backgroundColor instead of brightness and textTheme:

AppBar(
  backgroundColor: Colors.white,
  foregroundColor: Colors.black,
  title: Text('My App'),
)

Step 5: Address Platform-Specific Code

If your app uses platform channels, review your method channel code. Ensure return types properly handle nullability:

static Future<String?> getPlatformVersion() async {
  final String? version = await _channel.invokeMethod('getPlatformVersion');
  return version;
}

Step 6: Update Tests

Your tests will need updates to match the new type signatures. Common changes include:

// Before
expect(find.byType(RaisedButton), findsOneWidget);

// After
expect(find.byType(ElevatedButton), findsOneWidget);

Run your full test suite and fix failures one at a time:

flutter test

Common Migration Pitfal

ls

Pitfall 1: Mixed-Mode Projects

Running a partially migrated codebase leads to confusing errors. Either migrate everything at once or use the // @dart=2.9 header to explicitly mark files that have not been migrated yet. But do not leave files in mixed mode permanently.

Pitfall 2: Over-Using Nullable Types

The migration tool tends to make everything nullable when in doubt. This defeats the purpose of null safety. After the automated migration, spend time tightening types. If a value should never be null, do not mark it as nullable.

Pitfall 3: Ignoring Deprecation Warnings

Flutter 2.0 deprecates many APIs. These still work today but will be removed in future versions. Address deprecation warnings during migration rather than accumulating more technical debt.

Pitfall 4: Forgetting State Management Updates

If you use a state management solution like Provider, Bloc, or Riverpod, check that your state management code properly handles null safety. Provider 6.0, for example, has different behaviour around null values.

Performance Gains After Migration

In our experience migrating client applications, we have consistently observed:

  • Reduced crash rates by 15 to 30 percent due to null safety catching errors at compile time
  • Smaller build sizes thanks to the Dart compiler’s ability to optimise non-nullable types
  • Faster rendering from the improved Flutter engine
  • Better developer velocity as null safety reduces time spent debugging null reference errors

Post-Migration Verification

After completing the migration, run through this verification checklist:

  1. Full test suite passes with zero failures
  2. App launches and runs on both iOS and Android without errors
  3. No remaining deprecation warnings (or documented exceptions)
  4. flutter analyze reports no issues
  5. Release build completes successfully on both platforms
  6. Core user flows tested manually on physical devices
flutter analyze
flutter test
flutter build ios --release
flutter build appbundle --release

Moving Forward

Once you are on Flutter 2.0 with full null safety, staying current becomes much easier. The framework follows semantic versioning, and subsequent updates within the 2.x line are generally non-breaking.

We recommend establishing a regular update cadence, checking for Flutter updates monthly and applying them in a dedicated branch. This prevents the kind of large, risky migration that moving from 1.x to 2.x represents.

For Australian app teams working on production Flutter applications, the migration to Flutter 2.0 is well worth the investment. The stability gains from null safety alone justify the effort, and the improved tooling and widget library make daily development more productive.

If your team needs assistance planning or executing a Flutter migration, reach out to us at eawesome. We have guided multiple Australian businesses through this process and can help you migrate with confidence.