HomeArticles › Nine of My Commits in Flutter 3.47

Flutter 3.47.0 stable with nine commits by Ishaq Hassan inside it

Run flutter upgrade: Nine of My Commits Ship Inside Flutter 3.47

The release notes talk about Impeller on desktop and standalone Material. Underneath that headline sit 1,358 commits, and nine of them are mine.

By Ishaq Hassan · August 13, 2026 · 12 min read · Karachi, Pakistan

Flutter 3.47.0 went out on the stable channel on August 12, 2026, carrying Dart 3.13.0. If you ran flutter upgrade this week, you are now running some of my code.

That is not a figure of speech. Nine commits with my name on them are inside the 3.47.0 tag: seven in the framework and tooling, two more in the DevTools bundle that ships with it. Four of them are listed by number in the official release notes.

This article is the full accounting: what each commit actually does, which of them reached stable for the first time in this release, and, more usefully for you, exactly how to check whose code your own SDK is running instead of taking anybody's word for it.

Flutter 3.47 at a glance

What actually shipped on August 12

The headline features of 3.47 are the ones everyone wrote about: the Material and Cupertino libraries becoming standalone material_ui and cupertino_ui packages on pub.dev, Impeller becoming the default renderer on macOS, Windows and Linux, Widget Previews graduating to stable, and the Apple platform bump that raises the minimum to iOS 15 and macOS 12 ahead of Xcode 27.

Underneath those headlines, 3.47.0 is 1,358 commits ahead of 3.44.0, the previous stable. Flutter skipped 3.45 and 3.46 on the stable channel entirely, so this release swallowed nearly three months of merged work. Most of that work is invisible: a parameter here, a corrected doc comment there, a template fix that only matters when you create a new project.

A release is a headline plus a thousand small corrections. The headline gets the blog post. The corrections are what you actually hit on a Tuesday afternoon.

The nine commits, one by one

Two API additions you can use today

Add clipBehavior to AnimatedCrossFade (66 lines, 2 files). AnimatedCrossFade wrapped its children in a hardcoded ClipRect that you could not reach. Anything that painted outside the child bounds got sliced: box shadows, glows, and the stroke of a CircularProgressIndicator mid-crossfade. An earlier attempt to fix this by deleting the ClipRect outright was closed, because removing clipping silently changes existing layouts. So this one takes the boring path and exposes the knob instead, defaulting to Clip.hardEdge:

AnimatedCrossFade(
  duration: const Duration(milliseconds: 300),
  crossFadeState: state,
  clipBehavior: Clip.none, // shadows and indicator strokes survive now
  firstChild: const CardWithShadow(),
  secondChild: const CircularProgressIndicator(),
)

Add scrollPadding to DropdownMenu (37 lines, 2 files). DropdownMenu wraps a TextField internally, and TextField has always accepted scrollPadding, the padding kept around the field when the keyboard pushes it into view. DropdownMenu simply never forwarded it, so a dropdown at the bottom of a form would scroll to sit flush against the keyboard. SearchBar already exposed the property, which made the argument easy: this is a consistency gap, not a new idea.

DropdownMenu<String>(
  scrollPadding: const EdgeInsets.only(bottom: 120),
  dropdownMenuEntries: entries,
)

One template fix every new Android build inherits

Use double quotes in the settings.gradle.kts template (one line changed). When the plugin template was renamed from settings.gradle to settings.gradle.kts, the string stayed in Groovy style with single quotes. Kotlin only accepts single quotes for character literals, so the generated file was invalid Kotlin:

// before, invalid Kotlin
rootProject.name = '{{projectName}}'

// after
rootProject.name = "{{projectName}}"

One character on each side of a string, in a file nobody reads, that every generated Android plugin project starts from. That is the shape of the highest-leverage fixes: tiny diff, enormous blast radius.

Four documentation fixes that save real debugging hours

Docs commits are the ones people dismiss. They are also the ones that quietly delete entire afternoons from other engineers' lives.

Two DevTools fixes in the 2.60.0 bundle

Flutter 3.47 pins DevTools 2.60.0, up from 2.57.0 in the 3.44 line. Two fixes of mine ride in that jump:

Six of the nine reached stable for the first time

Here is the nuance most "my code shipped" posts skip, including my own first draft of this one on LinkedIn.

All nine commits are inside the 3.47.0 tag. But three of them, the Gradle template fix, the RouteAware doc correction and scrollPadding on DropdownMenu, all merged in March and already went out with 3.44.0 on May 18. They have been in production Flutter apps for three months. They are in 3.47 the same way every other commit in Flutter's history is: they were never removed.

The six that reached the stable channel for the first time in 3.47 are the four framework and test-API items from April, May and June, plus both DevTools fixes.

That gap is worth internalising if you contribute to Flutter. A merged pull request is not a shipped pull request. It lands on main, waits for a beta cut, then waits for a stable cut. My clipBehavior work merged on April 23 and reached stable users on August 12: 111 days between the purple badge and the first developer who could actually type clipBehavior: and have it compile. Flutter skipping 3.45 and 3.46 on stable stretched that queue further.

How to check whose code you are running

You should not believe any of the above because I wrote it. Every claim here is checkable in about a minute, and the same technique works for any contributor and any release.

1. Know your version.

flutter --version
# Flutter 3.47.0 · channel stable · Dart 3.13.0

2. Filter the release tag by author on GitHub. Commit listings accept an author filter as a query parameter, so this URL is the whole trick:

https://github.com/flutter/flutter/commits/3.47.0?author=ishaquehassan

Swap the tag for the version you are on and the username for whoever you are curious about. Your own name works too, and it is a good day when it does.

3. Ask your local SDK directly. Your Flutter install is a git clone, so it can answer this offline:

cd "$(dirname "$(readlink -f "$(which flutter)")")/.."
git fetch --tags
git log --oneline --author=ishaq 3.47.0 | cat

4. Settle a single pull request with a yes or no. Take the merge commit SHA from the pull request page and ask git whether it is an ancestor of the tag. Exit code zero means it is in that release:

git merge-base --is-ancestor 8303a3547509f32662be3a9cf1adc83bf41976fa 3.47.0 \
  && echo "in 3.47.0" || echo "not in 3.47.0"

The same question over the API, no clone required. A behind_by of zero means the tag already contains that commit:

gh api "repos/flutter/flutter/compare/<merge-sha>...3.47.0" \
  --jq '.status, .behind_by'

5. For DevTools, resolve the pin. DevTools is not in the Flutter repo, it is pinned by revision. Read the pin at the tag, then check your commit against that revision:

gh api "repos/flutter/flutter/contents/DEPS?ref=3.47.0" --jq .content \
  | base64 -d | grep dart_devtools_rev

That is how I confirmed the 3.47 pin is byte-identical to the v2.60.0 tag, and that 3.44 shipped 2.57.0. Five commands, zero trust required.

How to upgrade to Flutter 3.47, and what can break

If you are still on the 3.44 line, the upgrade itself is three commands:

flutter channel stable
flutter upgrade
flutter --version   # expect: Flutter 3.47.0 · Dart 3.13.0

Then flutter clean and flutter pub get in each project so old build artifacts and pinned constraints get regenerated. If something goes sideways, flutter downgrade steps you back to the SDK you had before.

Four things in this release are worth checking before you ship on it:

Intel Mac support is also being phased out, which matters if any of your build machines are still on Intel silicon.

Why the boring commits are the ones I am proudest of

Look at the list again. Two small API additions, one quoting fix in a template, four doc corrections, two tool bug fixes. Not one of them is clever. Nothing in there would survive a whiteboard interview as an impressive answer.

And that is exactly the point. The doc fix on CurvedAnimation will stop leaks that would never have produced a stack trace, just a slowly degrading app. The dragUntilVisible paragraph will save some engineer forty minutes of flipping a sign back and forth at 1 AM. The Gradle template fix is in the first file of every new Android plugin project created from here on.

Framework work is not glamorous. It is compounding. A fix merged once keeps paying every time somebody runs flutter create, and I will never meet a single one of them.

If you are waiting to find something impressive enough to contribute, that instinct is what is holding you back. Read the docs of a class you use daily with the assumption that they might be wrong. Look for the parameter the wrapper widget forgot to forward. That is where merged pull requests live, and it is the same list I have been working through from Karachi for the past year. My longer playbook on that is here.

Already merged for the next stable

Three more commits are merged and waiting on the next stable train:

Counting code changes only, and the AUTHORS line is a credit rather than a fix, that is eleven merged across the Flutter ecosystem so far. The full list, with links and status, lives on my contributions page.

Next time you run flutter upgrade, spend one minute on that commits URL with your own username in it. The first time it returns a row instead of an empty list is a very good feeling.


Want your name in a Flutter release?

I mentor engineers through exactly this path: picking a first issue that can actually merge, surviving review, and building a contribution record that shows up in the release notes. 13+ years of engineering, 11 merged PRs across the Flutter ecosystem, all of it done from Pakistan around a full-time job.

Get in touch →

FAQ

What is the latest stable version of Flutter?

As of August 13, 2026, Flutter 3.47.0 is the current stable release. It shipped on August 12, 2026 with Dart 3.13.0 and DevTools 2.60.0. The previous stable line was 3.44, ending at the 3.44.9 hotfix on August 6, 2026, because Flutter skipped 3.45 and 3.46 on the stable channel.

What is new in Flutter 3.47?

Standalone material_ui and cupertino_ui packages on pub.dev, Impeller as the default renderer on macOS, Windows and Linux, Widget Previews graduating to stable, and Apple platform prep that raises the minimum to iOS 15 and macOS 12 and makes the UIScene lifecycle mandatory under Xcode 27. Plus experimental Wasm deferred loading and multi-window improvements.

How do I upgrade to Flutter 3.47?

flutter channel stable, then flutter upgrade, then flutter --version to confirm. Run flutter clean and flutter pub get per project afterwards. flutter downgrade steps you back if you need it.

What can break when you upgrade to Flutter 3.47?

Four things: the iOS 15 and macOS 12 minimums, the mandatory UIScene lifecycle for UIKit apps built with Xcode 27, Impeller becoming the default desktop renderer (retest custom shaders), and the Intel Mac phase-out. Material and Cupertino also begin moving to standalone packages, with formal deprecation of the in-SDK libraries announced for the November stable.

When was Flutter 3.47.0 released and what is in it?

Flutter 3.47.0 hit the stable channel on August 12, 2026 with Dart 3.13.0. Headline changes: standalone material_ui and cupertino_ui packages, Impeller as the default renderer on macOS, Windows and Linux, Widget Previews graduating to stable, and the Apple bump to a minimum of iOS 15 and macOS 12.

How do I check which commits are inside a Flutter release?

Open github.com/flutter/flutter/commits/3.47.0 and append ?author=<username>, or run git log --author=... 3.47.0 inside your local SDK clone. For one pull request, take its merge SHA and run git merge-base --is-ancestor <sha> 3.47.0. Exit code zero means it is in the release.

Does a merged Flutter pull request ship in the next stable?

Not necessarily. Merged work lands on main, then rides a beta cut, then a stable cut. Flutter skipped 3.45 and 3.46 on stable, so March work shipped in 3.44.0 while April and May work waited for 3.47.0 in August. My clipBehavior change took 111 days from merge to stable.

What does clipBehavior on AnimatedCrossFade do?

AnimatedCrossFade always wrapped its children in a hardcoded ClipRect, which cut off shadows, glows and the stroke of a CircularProgressIndicator. Since 3.47 you can pass clipBehavior: Clip.none. The default stays Clip.hardEdge, so nothing changes unless you opt in.

Which DevTools version ships with Flutter 3.47?

DevTools 2.60.0, up from 2.57.0 in the 3.44 line. Two of my fixes ride in that bundle: the SplitPane range error when the child count changes between rebuilds, and the Network tab search field staying enabled after you clear recorded calls.


Also published on:

Dev.to Medium LinkedIn (original post)

Source of record:

3.47.0 release notes My commits on the 3.47.0 tag DevTools 2.60.0

Related reading

Ishaq Hassan is a Flutter Framework Contributor with 11 merged PRs across the Flutter ecosystem, listed in the official Flutter AUTHORS file, Engineering Manager at DigitalHire, and creator of the 35-video Urdu Flutter course listed on docs.flutter.dev. Karachi, Pakistan. ishaqhassan.dev.