Flutter SDK Version, Deprecation & Migration Reference
Freshness contract — read first.
Generated 2026-08-29. Stable at generation time: Flutter 3.47.2 (2026-08-27) bundling Dart 3.13.2.
Regenerate with python3 scripts/build_flutter_sdk_changelog.py --fetch (~4s; resolves the SDK from
$FLUTTER_ROOT or which flutter, no hard-coded paths).
Drift is detected by python3 scripts/check_freshness.py — exit 1 means the published stable moved
ahead of these files. If the gate fails, regenerate before answering any version question.
The gate itself is tamper-tested: python3 scripts/test_gate_tamper.py seeds five defects (stale
header, deleted minor row, wrong Dart floor, wrong first-stable row, emptied deprecation reference)
and requires exit 1 with the right reason for each, plus a green control run.
Rule 0 — never state a Flutter version from memory
Flutter ships a new stable minor roughly every 3 months, so any version fact held in model weights is stale by
construction. This skill exists because that staleness silently breaks pubspec.yaml bounds and CI.
- Version/Dart mapping → read
references/flutter-to-dart-version-matrix.md (generated).
- Deprecated symbol → read
references/widget-deprecations-and-replacements.md (generated, 217 members, Flutter 3.13 → 3.44).
- If the answer is not in either file, verify live before answering:
curl -s https://storage.googleapis.com/flutter_infra_release/releases/releases_macos.json | python3 -c "import json,sys; d=json.load(sys.stdin); h=d['current_release']['stable']; r=[x for x in d['releases'] if x['hash']==h][0]; print(r['version'], r['release_date'][:10], r['dart_sdk_version'])"
flutter --version # what THIS machine has
🎯 Highest-impact deprecations (verified against the 3.47 stable tree)
These are the ones that actually hit an app being upgraded. Full list in the generated reference.
| Deprecated |
Replacement |
First stable |
cacheExtent, cacheExtentStyle (all scroll views, viewports, reorderable lists) |
scrollCacheExtent |
3.44 |
ReorderableList.onReorder |
onReorderItem (it fixes the newIndex off-by-one for the removed item) |
3.44 |
SlideTransition / SizeTransition axisAlignment |
alignment (controls both axes) |
3.44 |
TextInput.setStyle |
updateStyle |
3.44 |
ImageFilter-carrying filter on render objects |
filterConfig |
3.41 |
CupertinoSheetRoute.builder / pageBuilder |
scrollableBuilder |
3.41 / 3.35 |
Expansible duration / curve / reverseCurve |
animationStyle |
3.41 |
Semantics.focusable, isFocusable |
focused (setting it implies focusable) |
3.38 |
findChildIndexCallback (ListView.separated, slivers) |
findItemIndexCallback (item indices, not child indices) |
3.38 |
SemanticsService.announce |
sendAnnouncement (multi-window safe) |
3.38 |
TickerMode.of / getNotifier |
TickerMode.valuesOf / getValuesNotifier |
3.38 |
Radio / RadioListTile / CupertinoRadio groupValue + onChanged |
wrap in a RadioGroup ancestor |
3.35 |
CupertinoDynamicColor value/red/green/blue/opacity/withOpacity |
component accessors .r/.g/.b/.a, toARGB32(), withValues() |
3.35 |
AppBarTheme.color |
backgroundColor |
3.35 |
DropdownButtonFormField.value |
initialValue |
3.35 |
Switch / SwitchListTile activeColor |
activeThumbColor (+ activeTrackColor) |
3.32 |
ExpansionTileController |
ExpansibleController |
3.32 |
Tooltip.height / TooltipThemeData.height |
constraints |
3.32 |
Color.withOpacity (dart:ui, not the framework tree) |
Color.withValues(alpha: …) — wide-gamut migration, avoids 8-bit precision loss |
3.27 |
MaterialState* family |
WidgetState, WidgetStateProperty, WidgetStatesController |
3.22 |
Form.onPopInvoked |
onPopInvokedWithResult |
3.24 |
WillPopScope |
PopScope(canPop:, onPopInvokedWithResult:) — required for Android predictive back |
3.13 |
textScaleFactor (all widgets) |
textScaler (nonlinear text scaling) |
3.13 |
Removed, not deprecated — hard build breaks
FlatButton → TextButton; RaisedButton → ElevatedButton; OutlineButton → OutlinedButton;
TextTheme.headline1…6 / bodyText1/2 / subtitle1/2 → displayLarge…bodyLarge/titleMedium;
ThemeData.accentColor → ColorScheme.secondary; Scaffold.of(context).showSnackBar →
ScaffoldMessenger.of(context).showSnackBar; ThemeData.toggleableActiveColor → per-widget
WidgetStateProperty. Verified absent from the 3.47 tree — these produce compile errors, not warnings.
🔗 Dart feature → required Flutter floor
A Dart language feature needs the Flutter release that bundles that Dart SDK. Derived from the generated matrix:
| Dart feature |
sdk: lower bound |
Implies Flutter >= |
| Primary constructors |
^3.13.0 |
3.47.0 |
| Private named parameters |
^3.12.0 |
3.44.0 |
Dot shorthands (.blue, crossAxisAlignment: .start) |
^3.10.0 |
3.38.0 |
| Sound flow analysis |
^3.9.0 |
3.35.0 |
Null-aware elements ([?maybe]) |
^3.8.0 |
3.32.0 |
Wildcard variables _ |
^3.7.0 |
3.29.0 |
| Digit separators |
^3.6.0 |
3.27.0 |
Pair this skill with dart-sdk-changelog for the Dart-side feature matrix.
🛠️ Runbooks
1. "What replaced X?" / analyzer reports a deprecation
- Grep the generated reference:
grep -i "<symbol>" references/widget-deprecations-and-replacements.md.
- Try the automated migration first — Flutter policy requires a data-driven fix with every framework
deprecation (
docs/contributing/Tree-hygiene.md), so this usually does the whole job:dart fix --dry-run # inspect
dart fix --apply # migrate
- Only hand-edit what
dart fix leaves behind, then flutter analyze.
2. Choosing environment: bounds for a package
- Decide the newest Dart language feature the code actually uses (see
dart-sdk-changelog).
- Set
sdk: '^<that Dart minor>'.
- Add the matching
flutter: floor from the matrix — never guess it:environment:
sdk: ^3.12.0
flutter: ">=3.44.0"
- Verify on the machine that will build:
flutter --version and dart analyze.
3. "What's new in Flutter X.Y?"
- Confirm X.Y is a real stable minor in the matrix (Flutter skips numbers: there is no stable 3.30, 3.33,
3.36, 3.40, 3.43 — those are dev/beta cycles only).
- State the bundled Dart SDK and release date from the matrix.
- List the deprecations whose
First stable equals X.Y from the generated reference.
- For anything beyond that, read the official release notes rather than guessing:
https://docs.flutter.dev/release/release-notes.
4. Rescuing a legacy Flutter app
- Read the current bounds from
pubspec.yaml and the matrix row for that Flutter minor.
- Step in stable minors, never in one jump — build and run tests at each stop.
- At each stop:
dart fix --apply, then flutter analyze, then run the app.
- Pre-3.0 (Dart < 2.12) apps must cross sound null safety first — that is a Dart-side migration; use
dart-sdk-changelog's legacy rescue guide before touching widgets.
- Material 3 is the default theme since Flutter 3.16; if the app pins
useMaterial3: false, treat the M3
switch as its own change with visual review, not a side effect of the upgrade.
5. Refreshing this skill (do this, do not patch numbers by hand)
cd <this skill directory>
python3 scripts/build_flutter_sdk_changelog.py --fetch # re-extracts the stable tree itself
python3 scripts/check_freshness.py # must print ALL FRESH, exit 0
The generator finds the Flutter SDK via $FLUTTER_ROOT, else which flutter, and needs it to be a git
checkout (standard git clone, Homebrew and fvm installs are). Pass --flutter-root PATH otherwise.
Then update the "Freshness contract" block and the highest-impact table if new buckets appeared — the
gate fails if that table disagrees with the generated data, so it cannot silently rot.
Automate it: run scripts/check_freshness.py on a schedule (cron / CI). It prints deterministic output
and exits non-zero only on real drift, so it is safe as a change-detector that wakes an agent up.
📌 Provenance and why this is not an upstream copy
Built after auditing RandalSchwartz/dart-sdk-skills
(MIT) on 2026-08-29. Its Dart half was adopted (see dart/dart-sdk-changelog); its Flutter half was rejected
and rebuilt here because it carried three defects that this design structurally prevents:
| Upstream defect |
Root cause |
Fix applied here |
| Version matrix ended at "Flutter 3.27 / 3.29 — Late 2024 / 2025", missing 6 stable minors and ~18 months |
hand-typed tables, and CI gates that only checked frontmatter, link targets and style ("e.g."/"i.e." bans) — never a version fact |
matrices are generated from releases_macos.json + the stable git tree, and a cron freshness gate fails when the published stable moves ahead of the file |
Flutter 3.27 / 3.29 → Dart 3.7 / 3.8 (both off by one; truth is 3.6.0 and 3.7.0) |
mapping written from memory |
mapping read from the release index, per release |
Color.withOpacity "deprecated in Flutter 3.22" |
recalled, not checked; the wide-gamut phase 1 actually landed in stable 3.27.0 (docs.flutter.dev/release/breaking-changes/wide-gamut-framework) |
deprecation versions derive from the @Deprecated marker in the source plus the documented beta→stable rule |
1---2name: flutter-sdk-changelog3description: Use when you need a Flutter version fact: which Dart SDK ships with a Flutter release, what the correct `environment:` bounds are for a language feature, what replaced a deprecated widget or property, what changed between two Flutter versions, or how to step a legacy Flutter app up to current stable. Every version number here is generated from Google's official release index and the flutter/flutter stable source tree, never from model memory.4---56# Flutter SDK Version, Deprecation & Migration Reference78> **Freshness contract — read first.**9> Generated **2026-08-29**. Stable at generation time: **Flutter `3.47.2`** (2026-08-27) bundling **Dart `3.13.2`**.10> Regenerate with `python3 scripts/build_flutter_sdk_changelog.py --fetch` (~4s; resolves the SDK from11> `$FLUTTER_ROOT` or `which flutter`, no hard-coded paths).12> Drift is detected by `python3 scripts/check_freshness.py` — exit 1 means the published stable moved13> ahead of these files. **If the gate fails, regenerate before answering any version question.**14> The gate itself is tamper-tested: `python3 scripts/test_gate_tamper.py` seeds five defects (stale15> header, deleted minor row, wrong Dart floor, wrong first-stable row, emptied deprecation reference)16> and requires exit 1 with the right reason for each, plus a green control run.1718## Rule 0 — never state a Flutter version from memory1920Flutter ships a new stable minor roughly every 3 months, so any version fact held in model weights is stale by21construction. This skill exists because that staleness silently breaks `pubspec.yaml` bounds and CI.22231. Version/Dart mapping → read [`references/flutter-to-dart-version-matrix.md`](references/flutter-to-dart-version-matrix.md) (generated).242. Deprecated symbol → read [`references/widget-deprecations-and-replacements.md`](references/widget-deprecations-and-replacements.md) (generated, 217 members, Flutter 3.13 → 3.44).253. If the answer is not in either file, verify live before answering:26 ```bash27 curl -s https://storage.googleapis.com/flutter_infra_release/releases/releases_macos.json | python3 -c "import json,sys; d=json.load(sys.stdin); h=d['current_release']['stable']; r=[x for x in d['releases'] if x['hash']==h][0]; print(r['version'], r['release_date'][:10], r['dart_sdk_version'])"28 flutter --version # what THIS machine has29 ```3031---3233## 🎯 Highest-impact deprecations (verified against the 3.47 stable tree)3435These are the ones that actually hit an app being upgraded. Full list in the generated reference.3637| Deprecated | Replacement | First stable |38| :--- | :--- | :--- |39| `cacheExtent`, `cacheExtentStyle` (all scroll views, viewports, reorderable lists) | `scrollCacheExtent` | 3.44 |40| `ReorderableList.onReorder` | `onReorderItem` (it fixes the `newIndex` off-by-one for the removed item) | 3.44 |41| `SlideTransition` / `SizeTransition` `axisAlignment` | `alignment` (controls both axes) | 3.44 |42| `TextInput.setStyle` | `updateStyle` | 3.44 |43| `ImageFilter`-carrying `filter` on render objects | `filterConfig` | 3.41 |44| `CupertinoSheetRoute.builder` / `pageBuilder` | `scrollableBuilder` | 3.41 / 3.35 |45| `Expansible` `duration` / `curve` / `reverseCurve` | `animationStyle` | 3.41 |46| `Semantics.focusable`, `isFocusable` | `focused` (setting it implies focusable) | 3.38 |47| `findChildIndexCallback` (`ListView.separated`, slivers) | `findItemIndexCallback` (item indices, not child indices) | 3.38 |48| `SemanticsService.announce` | `sendAnnouncement` (multi-window safe) | 3.38 |49| `TickerMode.of` / `getNotifier` | `TickerMode.valuesOf` / `getValuesNotifier` | 3.38 |50| `Radio` / `RadioListTile` / `CupertinoRadio` `groupValue` + `onChanged` | wrap in a `RadioGroup` ancestor | 3.35 |51| `CupertinoDynamicColor` `value`/`red`/`green`/`blue`/`opacity`/`withOpacity` | component accessors `.r/.g/.b/.a`, `toARGB32()`, `withValues()` | 3.35 |52| `AppBarTheme.color` | `backgroundColor` | 3.35 |53| `DropdownButtonFormField.value` | `initialValue` | 3.35 |54| `Switch` / `SwitchListTile` `activeColor` | `activeThumbColor` (+ `activeTrackColor`) | 3.32 |55| `ExpansionTileController` | `ExpansibleController` | 3.32 |56| `Tooltip.height` / `TooltipThemeData.height` | `constraints` | 3.32 |57| `Color.withOpacity` (dart:ui, not the framework tree) | `Color.withValues(alpha: …)` — wide-gamut migration, avoids 8-bit precision loss | 3.27 |58| `MaterialState*` family | `WidgetState`, `WidgetStateProperty`, `WidgetStatesController` | 3.22 |59| `Form.onPopInvoked` | `onPopInvokedWithResult` | 3.24 |60| `WillPopScope` | `PopScope(canPop:, onPopInvokedWithResult:)` — required for Android predictive back | 3.13 |61| `textScaleFactor` (all widgets) | `textScaler` (nonlinear text scaling) | 3.13 |6263### Removed, not deprecated — hard build breaks64`FlatButton` → `TextButton`; `RaisedButton` → `ElevatedButton`; `OutlineButton` → `OutlinedButton`;65`TextTheme.headline1…6` / `bodyText1/2` / `subtitle1/2` → `displayLarge…bodyLarge/titleMedium`;66`ThemeData.accentColor` → `ColorScheme.secondary`; `Scaffold.of(context).showSnackBar` →67`ScaffoldMessenger.of(context).showSnackBar`; `ThemeData.toggleableActiveColor` → per-widget68`WidgetStateProperty`. Verified absent from the 3.47 tree — these produce compile errors, not warnings.6970---7172## 🔗 Dart feature → required Flutter floor7374A Dart language feature needs the Flutter release that bundles that Dart SDK. Derived from the generated matrix:7576| Dart feature | `sdk:` lower bound | Implies Flutter `>=` |77| :--- | :--- | :--- |78| Primary constructors | `^3.13.0` | `3.47.0` |79| Private named parameters | `^3.12.0` | `3.44.0` |80| Dot shorthands (`.blue`, `crossAxisAlignment: .start`) | `^3.10.0` | `3.38.0` |81| Sound flow analysis | `^3.9.0` | `3.35.0` |82| Null-aware elements (`[?maybe]`) | `^3.8.0` | `3.32.0` |83| Wildcard variables `_` | `^3.7.0` | `3.29.0` |84| Digit separators | `^3.6.0` | `3.27.0` |8586Pair this skill with `dart-sdk-changelog` for the Dart-side feature matrix.8788---8990## 🛠️ Runbooks9192### 1. "What replaced X?" / analyzer reports a deprecation931. Grep the generated reference: `grep -i "<symbol>" references/widget-deprecations-and-replacements.md`.942. Try the automated migration first — Flutter policy requires a data-driven fix with every framework95 deprecation (`docs/contributing/Tree-hygiene.md`), so this usually does the whole job:96 ```bash97 dart fix --dry-run # inspect98 dart fix --apply # migrate99 ```1003. Only hand-edit what `dart fix` leaves behind, then `flutter analyze`.101102### 2. Choosing `environment:` bounds for a package1031. Decide the newest Dart language feature the code actually uses (see `dart-sdk-changelog`).1042. Set `sdk: '^<that Dart minor>'`.1053. Add the matching `flutter:` floor from the matrix — never guess it:106 ```yaml107 environment:108 sdk: ^3.12.0109 flutter: ">=3.44.0"110 ```1114. Verify on the machine that will build: `flutter --version` and `dart analyze`.112113### 3. "What's new in Flutter X.Y?"1141. Confirm X.Y is a real stable minor in the matrix (Flutter skips numbers: there is no stable 3.30, 3.33,115 3.36, 3.40, 3.43 — those are dev/beta cycles only).1162. State the bundled Dart SDK and release date from the matrix.1173. List the deprecations whose `First stable` equals X.Y from the generated reference.1184. For anything beyond that, read the official release notes rather than guessing:119 `https://docs.flutter.dev/release/release-notes`.120121### 4. Rescuing a legacy Flutter app1221. Read the current bounds from `pubspec.yaml` and the matrix row for that Flutter minor.1232. Step in **stable minors**, never in one jump — build and run tests at each stop.1243. At each stop: `dart fix --apply`, then `flutter analyze`, then run the app.1254. Pre-3.0 (Dart < 2.12) apps must cross sound null safety first — that is a Dart-side migration; use126 `dart-sdk-changelog`'s legacy rescue guide before touching widgets.1275. Material 3 is the default theme since Flutter 3.16; if the app pins `useMaterial3: false`, treat the M3128 switch as its own change with visual review, not a side effect of the upgrade.129130### 5. Refreshing this skill (do this, do not patch numbers by hand)131```bash132cd <this skill directory>133python3 scripts/build_flutter_sdk_changelog.py --fetch # re-extracts the stable tree itself134python3 scripts/check_freshness.py # must print ALL FRESH, exit 0135```136The generator finds the Flutter SDK via `$FLUTTER_ROOT`, else `which flutter`, and needs it to be a git137checkout (standard `git clone`, Homebrew and `fvm` installs are). Pass `--flutter-root PATH` otherwise.138Then update the "Freshness contract" block and the highest-impact table if new buckets appeared — the139gate fails if that table disagrees with the generated data, so it cannot silently rot.140141Automate it: run `scripts/check_freshness.py` on a schedule (cron / CI). It prints deterministic output142and exits non-zero only on real drift, so it is safe as a change-detector that wakes an agent up.143144---145146## 📌 Provenance and why this is not an upstream copy147148Built after auditing [`RandalSchwartz/dart-sdk-skills`](https://github.com/RandalSchwartz/dart-sdk-skills)149(MIT) on 2026-08-29. Its Dart half was adopted (see `dart/dart-sdk-changelog`); its Flutter half was rejected150and rebuilt here because it carried three defects that this design structurally prevents:151152| Upstream defect | Root cause | Fix applied here |153| :--- | :--- | :--- |154| Version matrix ended at "Flutter 3.27 / 3.29 — Late 2024 / 2025", missing 6 stable minors and ~18 months | hand-typed tables, and CI gates that only checked frontmatter, link targets and style ("e.g."/"i.e." bans) — never a version fact | matrices are **generated** from `releases_macos.json` + the stable git tree, and a cron freshness gate fails when the published stable moves ahead of the file |155| `Flutter 3.27 / 3.29 → Dart 3.7 / 3.8` (both off by one; truth is 3.6.0 and 3.7.0) | mapping written from memory | mapping read from the release index, per release |156| `Color.withOpacity` "deprecated in Flutter 3.22" | recalled, not checked; the wide-gamut phase 1 actually landed in stable **3.27.0** (docs.flutter.dev/release/breaking-changes/wide-gamut-framework) | deprecation versions derive from the `@Deprecated` marker in the source plus the documented beta→stable rule |