flutter-tools.nvim drives Flutter from Neovim and owns the dart language server
Tools to help create flutter apps in neovim using the native lsp
At a glance
- What is it?
- flutter-tools.nvim is a Neovim plugin that launches, debugs and hot reloads Flutter applications, exposes the language server's widget tree as an outline, and manages the dart language server itself, which is why the readme tells you not to configure dartls through lspconfig. It is Lua, MIT licensed, and needs Neovim 0.11 or newer.
- Who is it for?
- Adopt flutter-tools.nvim when you develop Flutter in Neovim and want one place that starts the app, picks the device, hot reloads and shows the widget tree, rather than a terminal beside the editor. Do not adopt it and then also configure dartls through lspconfig, because the readme is explicit that the plugin sets the language server up itself and that configuring both will conflict.
- 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 19 days ago.
- What is it written in?
- Mainly Lua, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One plugin for the app, the device and the widget tree
flutter-tools.nvim builds Flutter and Dart applications in Neovim using the native LSP. It adds the ability to easily launch Flutter applications, debug them, and extends the LSP functionality with things like the widget guides, an outline view of your widgets, and hot reloading.
The feature list is the proof of the scope. There is running a Flutter app with hot reloading, starting emulators or connected devices, visualising colours from the LSP, visualising logs, widget guides, an outline window, and closing tags.
That last group is the interesting one, because those are not features of the Flutter command line. The outline window shows the widget tree for a file, which is a view of the Dart API surface rather than of the text, and the closing tags feature helps you pair the closing tag of a widget with the widget you are editing. The colours from the LSP are the same idea, showing the actual colour of a `Colors.*` constant in the code rather than its name.
The plugin says it draws inspiration from emacs-lsp/lsp-dart, coc-flutter and nvim-metals, which is a useful signal about where the design came from.
There is a related plugin, flutter-icons.nvim, for inline Material icon previews rendered in completion docs, LSP hovers and inline in the code.
The implementation is Lua, the licence is MIT, and the last push was on 2026-10-06.
The plugin owns the language server, and that is a warning
The readme has a Warning section, and it is the first thing to read before configuring anything.
Flutter tools does not depend on nvim-lspconfig. The two can co-exist but you should ensure you do not configure dartls using lspconfig, because it will be automatically set up by this plugin instead.
So the plugin starts and manages the dart language server itself. That is a deliberate choice and it has a consequence: if you also configure dartls through the usual lspconfig path, you end up with two language servers, or with one fighting the other, and the symptom is duplicated diagnostics and two completion sources.
The same boundary is stated in the LSP client section, which says the plugin only enhances and adds to the functionality provided by Neovim and does not by itself provide autocompletion, code actions, or configure how errors from the language server are displayed. All of that is handled by configuring the LSP client.
The readme is careful to say that the minimal native LSP configuration it shows is not a replacement for reading the documentation, only a demonstration of what some basic setup might look like, and it points at the lsp help topic and the nvim-lspconfig README.
" Show hover
nnoremap K <Cmd>lua vim.lsp.buf.hover()<CR>The division is sensible, and the warning is the price of it. The plugin takes the language server so it can restart it, and so it can wire the Flutter specific features into it, and the price is that you cannot use the standard path for that one server.
Installing it, and the two dependencies you must not forget
The prerequisites are short. Neovim 0.11 or newer is required.
The installation section gives two routes, and the first uses lazy.nvim.
{
'nvim-flutter/flutter-tools.nvim',
lazy = false,
dependencies = {
'nvim-lua/plenary.nvim',
},
config = true,
}The second uses vim.pack, which is built into Neovim 0.12 and later, and you can see it in the help.
vim.pack.add({
'https://github.com/nvim-lua/plenary.nvim',
'https://github.com/nvim-flutter/flutter-tools.nvim',
})
require('flutter-tools').setup {}The first dependency is plenary.nvim, and the readme is emphatic that it is a dependency and must be installed.
The second is quieter and more interesting. The plugin depends on vim.ui.select, which lets users control what UI is used for selecting from a list of options. If you have no UI configured for vim.ui.select, you need a picker, and the readme names the usual candidates, snacks.nvim, fzf-lua, mini.pick and telescope-ui-select.
That dependency is a design decision worth noticing. The plugin does not implement a picker, it uses the Neovim standard interface for one, so your existing picker choice carries over and the plugin does not force a UI on you. The cost is that a fresh Neovim configuration with no picker at all will not work until you add one, and the error will be about a missing select implementation rather than about Flutter.
Setup is one call, from either language
The Setup section offers the same configuration in two languages, and the point is that you do not have to leave Vimscript to use it.
In Vimscript, the call is wrapped in a lua heredoc.
lua << EOF
require("flutter-tools").setup {} -- use defaults
EOFIn Lua it is a single line.
require("flutter-tools").setup {} -- use defaultsThe empty braces are the defaults, and the readme points at a full configuration section further down for the settings, of which two are worth naming because they change behaviour in ways that are not obvious.
The first is config.debugger.enabled, which FlutterRun respects. So whether the run command starts a debug session or a plain run is a configuration choice rather than a hard coded behaviour.
The second is the devices.args setting, which passes extra arguments to the flutter devices command. The readme gives the example of {"--device-connection", "attached"} to skip the slow wireless device scan, which is a real problem on a desk with several devices in range, because the default scan has to wait for the wireless ones to answer.
There is a similar override for emulators. Setting emulators.launcher starts the selected emulator with your own command instead of flutter emulator --launch, which is how you use a launcher that is already running or a custom script.
The command surface is long and mostly about the running app
The Usage section is a long list, and reading it tells you what the plugin considers part of a Flutter development session.
There is FlutterCommands, which picks a flutter-tools command from a list shown with your vim.ui.select UI, and FlutterFvm, which picks a Flutter SDK installed with fvm and switches the project to it. The second is a real convenience for anyone whose project pins an SDK version, since the global flutter on the machine is rarely the one the project wants.
The running and debugging commands are FlutterRun, which respects the debug setting, and FlutterDebug, which forces debug mode. FlutterDevices brings up a list of connected devices to select from, and FlutterEmulators does the same for emulators, with the configuration overrides described earlier.
The lifecycle commands are FlutterReload, FlutterRestart, FlutterQuit, FlutterAttach and FlutterDetach. The last of these is the subtle one: it ends a running session locally but keeps the process running on the device, which is how you detach from a long running app without killing it.
The inspection commands are FlutterOutlineToggle and FlutterOutlineOpen for the widget tree, FlutterVisualDebug, FlutterInspectWidget for widget inspection, and FlutterChangeTargetPlatform to cycle the target platform override and FlutterToggleBrightness for the app brightness override.
The tooling commands are FlutterDevTools to start a Dart Dev Tools server, FlutterDevToolsActivate to activate one, FlutterOpenDevTools to open the connected page, and FlutterCopyProfilerUrl, which copies the profiler URL to the system clipboard and requires FlutterRun and FlutterDevTools to have been executed first.
And there are the project ones, FlutterPubGet and FlutterPubUpgrade with optional extra arguments, and FlutterLspRestart, which restarts the dart language server and is intended for the situations where it begins to misbehave.
Widget guides, closing tags and statusline decorations
Three of the features deserve a note, because they are the ones that go beyond wrapping the flutter command.
The widget guides are marked experimental, with a default of disabled, and the screenshot is of the guide rather than of the outline. The distinction between the two is worth keeping: the outline shows the widget tree for the file you are in, and the guide appears to be the in-editor explanation of a widget, which is why it is experimental and off by default.
The closing tags feature is a small editor nicety that solves a genuine annoyance in Flutter code, where a build method returns a deep tree of widgets and the closing bracket is far from the opening one.
The statusline decorations are the app version and the related entries, and they are the kind of feature that decides whether a plugin gets kept in a configuration, because a statusline segment that shows the version of the app you are running is the sort of thing you notice when it is missing.
The visualising of logs is the other one to mention, because the plugin shows the dev log rather than sending you to a terminal, and combined with the run and reload commands that means the whole loop of edit, hot reload and read the output happens inside the editor.
For the record, there is also a note that you might encounter issues using this plugin on the master channel of Flutter, which is the project telling you that the bleeding edge of the SDK and the bleeding edge of the plugin do not always line up.
The repository layout and a version jump
The top level listing shows a conventional Neovim plugin repository with a couple of extras.
There is lua/ for the plugin code, syntax/ for the syntax files, ftplugin/ for the filetype plugin, doc/ for the Vim help documentation, and tests/ for the test suite. There is a stylua.toml, which is the formatter configuration for the Lua code, and a.luarc.json for the Lua language server, plus a.nvim.json for the Neovim specific settings.
The release history is the interesting part. The tags are v3.2.0 from 2026-10-06, v1.14.0 from 2024-08-30 and v1.13.0 from 2024-08-23.
So the project jumped from a 1.x line to a 3.x line, and the two older tags are a week apart in August 2024, which suggests the 1.x line was where the project sat for a long time and the 3.x line is a new series.
The prerequisites explain part of it. Neovim 0.11 is required, and the vim.pack installation route needs Neovim 0.12 or newer, so the plugin tracks recent Neovim releases closely, and a version bump that follows a Neovim release is a reasonable way to use up a new API.
There is a CHANGELOG.md and a CONTRIBUTING.md in the repository, and the licence is MIT.
Editorial conclusion
Adopt flutter-tools.nvim when you develop Flutter in Neovim and want one place that starts the app, picks the device, hot reloads and shows the widget tree, rather than a terminal beside the editor. Do not adopt it and then also configure dartls through lspconfig, because the readme is explicit that the plugin sets the language server up itself and that configuring both will conflict. Verify first that you are on Neovim 0.11 or newer, that plenary.nvim is installed, that a vim.ui.select implementation exists, and that the widget guides are switched on deliberately, since they are experimental and disabled by default.
Frequently asked questions
What does flutter-tools.nvim do?
It lets you build Flutter and Dart applications in Neovim using the native LSP, adding the ability to launch Flutter applications, debug them, and extend LSP functionality with widget guides, an outline view of the widgets, and hot reloading.
Do I still need to configure the dart language server?
No, and you should not. The readme warns that the plugin does not depend on nvim-lspconfig, that the two can co-exist, and that you must not configure dartls with lspconfig because it is set up automatically by the plugin instead.
What do I need to install flutter-tools.nvim?
Neovim 0.11 or newer, the plenary.nvim dependency, and an implementation of vim.ui.select, since the plugin uses that interface to show pickers and does not ship its own. The readme names snacks.nvim, fzf-lua, mini.pick and telescope-ui-select as options.
How do I set the plugin up?
With a single call, either require("flutter-tools").setup {} in Lua or the same call inside a lua heredoc in Vimscript. The defaults are usable as they are, and the readme points at a full configuration section for the rest.
How do I make the device list load faster?
Set devices.args to pass extra arguments to flutter devices. The readme gives {"--device-connection", "attached"} as the example, which skips the slow wireless device scan.
What is the difference between FlutterDetach and FlutterQuit?
FlutterQuit ends a running session, while FlutterDetach ends a running session locally but keeps the process running on the device.
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/nvim-flutter-flutter-tools-nvim)Was this useful?