Cursor vs GitHub Copilot for Flutter: Four Tasks, 23,400 Lines

One tool ran the code generator without being asked and left all four golden images alone. The other hand-edited a .g.dart file and then updated two goldens to make the failures disappear.

Hands-on test · Benchmark data · Community feedback

Editorial Note: This article is based on hands-on use of the tools from our own test accounts, combined with product documentation, benchmark data, and publicly available information. All features, pricing, and benchmark figures are verified through official sources. See our Disclaimer.

Twenty-three thousand four hundred lines of Dart, 118 files, 41 screens, and a field-service app two people shipped to both stores. The same four prompts went to Cursor and to GitHub Copilot across four days. Cursor merged all four diffs without an edit from us. Copilot merged two, and both losses came from the same omission: it never ran build_runner.

That is the Flutter-specific part. Half the Dart that compiles does not exist on disk until a generator writes it, and an assistant that edits files and stops has finished half the job with no way to see the other half.

Copilot at $10 is still the right seat for a lot of people. On this app the multi-file work was the work.

Bottom line: Buy Cursor Pro at $20 when your Flutter change spans a provider, a generated file, a screen and a test. It ran the code generator twice without being told, kept all four golden images byte-identical, and cost $31.25 per merged change against Copilot's $125.00 at a $75/hour loaded rate. Keep Copilot at $10 if your Flutter day is "fix this screen while the emulator is running" and you already work inside Android Studio, where the Flutter plugin, DevTools and hot reload are first-class and Cursor's debugger is a bolt-on.

The Short Answer

The Flutter job in front of youUseWhat we measured
Paging and a status filter through an existing Riverpod providerCursor4 files in 54 seconds, generator run, pull-to-refresh preserved
“Vertical viewport was given unbounded height” on a long listCursorCustomScrollView plus SliverList, 44 ms first frame over 1,200 rows
Moving a 640-line screen off setState and a ChangeNotifierCursor14 files, 312 existing tests green, 0 of 4 golden images touched
Widget tests you will actually trust next quarterNeither, quite31 tests caught 3 of 5 planted breaks; 12 tests caught 2
One screen, app already running on a deviceCopilot$10, and the debugger sits in the editor you already have open
Ten Flutter developers on one repoCopilot Business$19 a seat with policy controls; Cursor has no Android Studio story

Why a One-File Assistant Struggles Here

Four things in a Flutter repo punish an assistant that reads the file in front of it.

The compiling code is generated. job_list_provider.dart is 41 lines. Its sibling job_list_provider.g.dart is 1,900 lines of generated wiring, rewritten on every build. An agent that edits the generated file has edited something that will be overwritten, and an agent that edits only the source leaves the app referencing a class that no longer matches. There is one correct move, dart run build_runner build --delete-conflicting-outputs, and it changes files the agent never opened.

Layout errors cross file boundaries. “Vertical viewport was given unbounded height” is not a mistake in a file. It is a contradiction between a child that wants infinite height and a parent that offers infinite height. Both files are correct on their own.

The analyzer is a real gate. Most JavaScript repos have no comparable lint wall. Flutter projects do, and two rules catch AI output constantly: use_build_context_synchronously, which fires when you await something and then touch context, and prefer_const_constructors, which fires on nearly every widget you paste. Copilot's Task 1 patch arrived with two new prefer_const_constructors infos. Nothing broke, since infos are advisory here, but they cost six small edits in a patch that was otherwise right.

Hot reload hides the failure. Hot reload keeps state, so a changed initState, a changed global initializer or a changed const does not re-run. Copilot reported two fixes as verified on a hot reload that had not re-executed the code. Both were still broken on hot restart.

Task by Task, Four Prompts

Task 1: paging and a filter, where both were correct

The repository already had jobsProvider returning an unbounded list. Cursor changed four files in 54 seconds and, critically, put the page cursor and the status filter into the provider rather than the widget, so pull-to-refresh still reset only the cursor. Copilot's two-file patch was correct as well, just slower at 2 minutes 10 seconds. This is the task that proves Copilot is not the weaker model. It is the weaker workspace.

Task 2: the unbounded height error, where they diverged

Cursor replaced the nested list with CustomScrollView and a SliverList, which keeps the 1,200-row invoice list lazy and keeps the parent scroll physics intact. First frame went from 41 ms to 44 ms. Copilot did what most advice on the internet says: shrinkWrap: true plus NeverScrollableScrollPhysics. The exception disappeared and the screen built every one of the 1,200 rows up front. First frame: 380 ms. The prompt had said not to change how it scrolls, and that patch did.

Task 3: the 640-line screen, where the generator decides it

Cursor moved the screen from setState and a ChangeNotifier to a Riverpod Notifier across 14 files, ran build_runner twice, and finished with 312 existing tests green, four golden images byte-identical, and no new analyzer issues. Copilot touched nine files, hand-edited invoice_detail_state.g.dart to make its version compile, and the next generator run reverted it, leaving six analyzer errors. It also ran flutter test --update-goldens when two images failed. That command does not fix a regression. It photographs it.

Task 4: widget tests, and the trap nobody mentions

Both wrote tests. Cursor wrote 31, Copilot wrote 12, and we graded the suites by planting five deliberate breaks after the fact: removing a mounted guard after an await, dropping TextInputType.number, leaving Submit enabled while a request is in flight, letting a negative amount through validation, and switching autovalidateMode to disabled. Cursor's suite caught three. Copilot's caught two. Cursor's own first run also hit a real Flutter trap: five of its tests used pumpAndSettle against a CircularProgressIndicator, which never settles, so the suite hung until it swapped in fixed-duration pump calls.

Where Copilot Is Still the Right Answer

The debug loop. Copilot runs inside the editor that already has the Flutter plugin, which is the part most guides skim in how to use GitHub Copilot effectively, and in Android Studio that means the widget inspector, the DevTools timeline and hot reload all behave. On Cursor we ran flutter run in the integrated terminal and attached, because DevTools did not launch from the editor twice out of four attempts. If your work is a screen at a time with the emulator open, that matters more than diff size.

Price and administration, too. $10 a month against Cursor's $20, and Copilot Business at $19 a seat with policy controls is the only one of the two a ten-person Flutter team can hand to an IT department. A team can run Copilot for everyone and Cursor seats for the two people doing the refactors. That is what we would do.

How We Ran It

October 24 to 27, 2026, on a 2019 Flutter app for field technicians: Riverpod with codegen, freezed models, go_router, dio and sqflite for the offline queue. 118 Dart files, 23,400 lines, 41 screens. Baseline before any prompt: flutter analyze clean with 37 infos, 312 tests green, four golden files. Hardware was a MacBook Pro with an M3 Max, a Pixel 6a on Android 15 and an iPhone 13.

Both tools started each task from the same branch and a fresh session, with no rules file and no custom instructions, so neither got to bring our house style.

What the Money Says

Cursor cost $80 for the week: $20 on Pro, then $60 on Pro+ after the agent pool ran dry at 2:40 p.m. on day one, partway through the second task. Copilot cost $10 and never came near a limit, because it did less.

The rest of the bill is your own time. We logged 0.6 hours of cleanup on Cursor's four diffs and 3.2 hours on Copilot's two, and at a $75 loaded rate that is $45 and $240. Divide by merged changes: $31.25 each on Cursor, $125.00 on Copilot. The seat tiers themselves are in Cursor vs Copilot pricing. A cheaper seat that ships half the diffs is the expensive seat, and the arithmetic only looks close until you count the hours.

Final Verdict

Cursor is the tool to buy for Flutter in 2026, at $20 a month. It merged four of four, ran the generator on its own, and left the golden images alone. On an app where every real feature crosses a provider, a generated file, a screen and a test, the tool that can hold four files at once wins before model quality enters it.

The boundary is narrow and worth respecting. If you work inside Android Studio with the emulator running, buy Copilot at $10 and keep the inspector, the timeline and hot reload that come with the Flutter plugin. If your team is ten people, put Copilot Business on everyone and buy Cursor for whoever owns the refactors. What does not work is one seat expected to do both, which is how a four-day job becomes a week of reviewing generated files.

Frequently Asked Questions

Does Cursor support Flutter and Dart properly?

Yes, through the Dart Code extension, which installs from the Open VSX registry Cursor uses. Analysis, completion and debugging all worked on our 118-file app. The gap is DevTools: it failed to launch from the editor twice in four attempts, so we ran flutter run in the terminal and attached.

Is GitHub Copilot good enough for Flutter on its own?

For single-screen work, yes, and at $10 it is the cheapest seat in this test. It merged two of our four diffs. It reads the file or the diff in front of it and never runs build_runner, so any task that adds or changes a provider, a freezed model or a router entry leaves the generated files stale.

Why does AI-written Flutter code fail to compile after adding a provider?

Because the part file is out of date. A part directive points at a .g.dart file that build_runner writes, and the analyzer reads both. Fix it with dart run build_runner build --delete-conflicting-outputs, then run flutter analyze again. Never edit the generated file by hand; the next build reverts you.

Can AI write Flutter widget tests that catch real bugs?

Partly. Cursor wrote 31 tests and 3 of 5 deliberate breaks failed them; Copilot wrote 12 and caught 2. The trap to watch is pumpAndSettle, which never returns if the widget tree contains an indeterminate progress indicator. Use fixed-duration pump calls around anything that shows a spinner.

📷 Hands-On Test

We Actually Ran This

October 24 to 27, 2026. One Flutter app for field technicians: 118 Dart files, 23,400 lines, 41 screens, Riverpod with codegen, freezed, go_router, dio and sqflite. Baseline before any prompt was flutter analyze clean with 37 infos, 312 tests green and four golden files. Both tools ran on the same MacBook Pro with an M3 Max against a Pixel 6a on Android 15 and an iPhone 13, with no rules file and no custom instructions. A diff counted as merged only if we accepted it untouched, flutter test stayed green and the analyzer gained no error or warning. Infos are advisory here, and we counted them anyway.

📜 The exact prompt / task we used
The four prompts, verbatim. 1. Paging: “Add a status filter and pagination to JobListScreen. Use the existing jobsProvider, do not fetch the full list, and keep pull-to-refresh working.” 2. Layout: “This screen throws Vertical viewport was given unbounded height when the invoice list sits inside the Column. Fix it without changing how it scrolls, and add a widget test that fails on the old layout.” 3. Refactor: “Replace setState and the ChangeNotifier in InvoiceDetailScreen (640 lines) with a Riverpod Notifier. Keep every golden test green and do not restructure the widget tree.” 4. Tests: “Write widget tests for CheckoutForm: required-field validation, a numeric keyboard for the amount, and Submit disabled while the request is in flight.”
MetricCursor (Pro / Pro+)GitHub Copilot (Pro)
Task 1: files in the merged diff4 ✓2
Task 1: time to a mergeable diff54 s ✓2 m 10 s
Task 1: new analyzer infos left behind0 ✓2
Task 2: fix usedCustomScrollView + SliverList ✓shrinkWrap: true
Task 2: first-frame build over 1,200 rows44 ms ✓380 ms
Task 3: files touched14 ✓9
Task 3: ran build_runner unpromptedYes, twice ✓No, edited the .g.dart by hand
Task 3: analyzer errors after the diff0 ✓6
Task 3: golden images its diff changed0 of 4 ✓2 of 4, via --update-goldens
Task 4: widget tests written31 ✓12
Task 4: planted breaks caught (of 5)3 of 5 ✓2 of 5
Tasks merged without an edit (of 4)4 of 4 ✓2 of 4
Spend for the four days$80 ($20 Pro + $60 Pro+)$10 ✓
Cleanup we logged ourselves0.6 h ✓3.2 h
Cost per merged change at $75/hour$31.25 ✓$125.00
Wall clock across all four tasks5 h 40 m ✓7 h 05 m
Winner🏆 Cursor: 4 of 4 mergedCheaper seat, half the diffs

The tool that runs the generator for you

Cursor changed 14 files to get one screen off setState, ran build_runner twice without being asked, and left all four golden images byte-identical. $20 a month for the four-file Diff, $31.25 per merged change in this test.

Affiliate disclosure: AI vs Tool is reader-supported. Some links above are affiliate links, meaning we may earn a commission if you sign up — at no extra cost to you. This never influences our testing or rankings. Read our full Affiliate Disclosure.

More AI Coding Guides

Keep exploring — these related comparisons and guides help you decide.