fvm: one Flutter SDK version per project, many versions on disk
Flutter Version Management: A simple CLI to manage Flutter SDK versions.
At a glance
- What is it?
- A Dart CLI that keeps several Flutter SDKs installed at once and pins one to each project, so testing a new Flutter release stops meaning a full reinstall.
- Who is it for?
- fvm earns its place the moment a team has two Flutter versions in flight, because the expensive part of channel switching is the download rather than the selection. What the repository front page does not tell you is how a pin is stored, whether it travels in version control, and what happens when a channel is retired, and those answers live on fvm.app rather than in the README.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Dart, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The six problems behind the channel switch
The pitch is one sentence: fvm manages Flutter SDK versions per project and switches between them instantly without reinstalling. Everything after that sentence is a list of six separate pains, which is more precision than most READMEs in this space offer. You need several SDKs at once. Testing a release means changing channel. Channel switches are slow and need repeated reinstalls. It is hard to remember which SDK version last worked for an app. Flutter major updates can demand a total app migration. And development environments drift apart inside a team.
Those are not hypothetical. Each one maps to a distinct failure mode, and the fourth is the interesting one, because it is a bookkeeping problem rather than a performance problem. Knowing which version your app last built on is worth more than building fast when the app is large.
The repository reports 5,523 stars, 285 forks and 39 open issues, under the MIT license, written in Dart. The distribution shape is broader than a typical pub.dev package: alongside the Dart source in `lib/` and `internal/`, the tree carries `fvm.nuspec` for Windows packaging and three separate JSON manifests named for Linux, macOS and Windows. Publishing reaches pub.dev, GitHub binaries, Homebrew, Chocolatey and Docker images.
Reference counting SDKs before deleting them
The most interesting thing in fvm's recent history is not a command but a data structure. Version 4.2.0, released on 2026-08-23, added a `Projects` column to `fvm list` that reports how many known projects pin each cached SDK. A day later, 4.3.0 used that same knowledge to add `fvm cleanup`, which previews unused cached SDKs and exact same-line stable patch upgrades, and deletes them with `--remove-unused`.
The subtlety is in what gets deleted. Recommended upgrade targets stay cached until a project or global pin moves, so cleanup does not remove the version the CLI wants to suggest upgrading to. The `Unused` label in `fvm list` was repointed at the new logic, which means the display and the destructive action share one definition rather than two.
There is a scriptable counterpart. `fvm api cleanup` reports three things: `upgrades`, `unused`, and `removable`. The documentation states that `unused` matches what `fvm list` calls Unused and what `fvm api list` calls `unreferencedVersions`, while `removable` is the set `--remove-unused` would actually delete. Two different sets for the same cache is a deliberate choice, and it is the kind of detail that saves you from a surprising deletion.
Three releases landed in twelve days: 4.2.0 on 2026-08-23, 4.3.0 on 2026-08-24, and 4.3.1 on 2026-09-04. The last one waited for proxied Flutter commands to finish their cleanup after Ctrl+C before exiting with status 130, which stops terminals being left in raw mode, and made dependency resolution accept both pub_updater 0.4 and 0.5 while keeping Dart 3.6 compatibility.
The front page of the repository documents shipping, not using
This is the first thing worth knowing about the README, because it will waste your time if you go in expecting a quick start. The GitHub front page has six sections: Why FVM, Release Process (For Maintainers), Contributors, a pointer to a companion product, Troubleshooting, and License. There is no install command and no usage example anywhere on it.
Usage documentation lives elsewhere. The Why FVM list links to a getting started guide on fvm.app, and the Troubleshooting section is a single sentence pointing at that site's FAQ. So the repository you read while evaluating the tool is largely a maintainer handbook. Judge the CLI from the documentation site and treat this README as a second artifact.
The maintainer half is detailed, though. Creating a release means merging everything on main, creating a GitHub release with a semver tag that carries a `v` prefix (the documented example is `v4.0.0-beta.2`), writing the notes in the GitHub editor, and publishing. `.github/workflows/release.yml` then fires and deploys to pub.dev, GitHub binaries, Homebrew, Chocolatey and Docker, with progress visible in the Actions tab. Emergency releases take a different path: edit the version in `pubspec.yaml` by hand, then trigger `deploy_homebrew.yml` or `deploy_docker.yml` through manual dispatch. For a full emergency deployment you still create a normal GitHub release.
The last push on the default branch was 2026-09-21, and the newest release is 4.3.1 from 2026-09-04.
Two Dart toolchains, because the tool manages toolchains
The README's Dart note is short and it quietly undercuts the whole premise of the tool. Day-to-day development targets the repository's own SDK constraint, `>=3.6.0 <4.0.0`. Release automation lives under `tool/release_tool/` and needs Dart 3.8.0 or newer. Continuous integration pins that higher toolchain through the `RELEASE_DART_SDK` environment variable, currently set to 3.9.0, so the versions packaged for Homebrew and the other installers match what is built in CI.
So contributing to a Flutter version manager requires switching Dart SDKs depending on the task, which is either a nice bit of self-reference or an awkward admission that the bootstrap problem never goes away. Release work is the part that matters more, because that is what produces the artifacts you install, so the README's advice is to switch to Dart 3.8.0 or newer before running anything from `tool/release_tool/`.
The lower bound is actively defended rather than drifting. The 4.3.1 release widened dependency resolution to accept both pub_updater 0.4 and 0.5 at once while explicitly retaining Dart 3.6 compatibility, which is the awkward part of any library that supports two major versions of its own tooling dependency. That change shipped alongside the Ctrl+C cleanup fix, so the release mixes a user-visible terminal bug with dependency plumbing.
If you are reading this to decide whether to adopt fvm rather than to patch it, none of this matters. If you are reading it to contribute, the Dart requirement table above is the first thing to get right.
Beyond the CLI: MCP exposure, sidekick, and CI scaffolding
The tree is worth reading past `lib/`. There is an `fvm_mcp/` directory, which means the CLI is exposed to agents over the Model Context Protocol. For a tool whose entire job is answering the question of which Flutter version a given project resolves to, that is a natural fit rather than a bolted-on extra.
There is also `example/`, `test/`, `tool/`, `scripts/`, `docs/` and `setup.sh` at the top level, plus the usual developer scaffolding: `.husky/` for git hooks, `analysis_options.yaml` for the Dart analyzer, and `dart_test.yaml`. Both `.actrc` and a `.docker/` directory are present, which suggests the test suite can be run through act rather than only on hosted runners. `AGENTS.md` and `CHANGELOG.md` sit alongside them.
The README closes by pointing at Flutter Sidekick, a separate repository by the same author, and routing troubleshooting to the documentation site's FAQ. Neither is a dependency; both are the natural next click.
What none of this settles is how a pin is represented. Whether the per-project selection is a checked-in config file or a local one, whether the cache is shared across machines or duplicated per user, and what happens to a pin when Flutter retires the channel it names are all questions the front page does not reach. Those are documented on fvm.app, and they are the questions that determine whether fvm fits a team that wants the same SDK version in CI and on every laptop.
Editorial conclusion
fvm earns its place the moment a team has two Flutter versions in flight, because the expensive part of channel switching is the download rather than the selection. What the repository front page does not tell you is how a pin is stored, whether it travels in version control, and what happens when a channel is retired, and those answers live on fvm.app rather than in the README. Start with the getting started guide for a single project, then read the FAQ, and only afterwards care about the cache cleanup work that arrived in the 4.2 and 4.3 releases.
Frequently asked questions
What does fvm actually do?
It keeps several Flutter SDKs installed side by side and selects one per project, so changing versions does not mean downloading an SDK again. The README frames the whole problem around channel switching: testing a release requires changing channels, and channel switches are slow and need repeated reinstalls.
Does fvm replace Flutter?
No. fvm is a Dart CLI that manages Flutter SDK installs on disk, distributed through pub.dev, Homebrew, Chocolatey and Docker images. The Flutter SDK itself is untouched. What fvm changes is which SDK a project resolves to, not what that SDK contains.
Which Dart version do I need to work on fvm?
Two, depending on the task. Day-to-day work targets the repository constraint of Dart 3.6.0 and above but below 4.0.0, while release tooling under tool/release_tool/ needs 3.8.0 or newer, with CI pinning 3.9.0 through the RELEASE_DART_SDK variable.
How does fvm avoid filling the disk with unused SDKs?
It counts references before deleting anything. The 4.2.0 release added a Projects column to fvm list showing how many known projects pin each cached SDK, and 4.3.0 added fvm cleanup to preview unused versions and remove them with --remove-unused, while keeping recommended upgrade targets cached.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/leoafarias-fvm)