A package that compiles on my laptop is not a package FlutterFlow will build.
That gap has shaped more of my FlutterFlow work than any decision about Dart. Across eight marketplace templates and more than forty custom widgets, the question I answer before designing anything is not whether the widget can be written. It is whether the dependency it needs will survive the cloud build. When someone searches for why their FlutterFlow custom code package is not working, they are almost never staring at a syntax error. They are standing on the seam between a package that assumes an ordinary Flutter project and a build system that is not one.
If the vocabulary here is new, start with what Flutter actually is and how it differs from a wrapper, then come back.
Why is your FlutterFlow custom code package not working?

Usually because it needs something the cloud build cannot give: native platform code, missing web support, or a version FlutterFlow has already pinned.
Notice what is absent from that list. Your code. The widget you wrote is usually fine. What fails is the resolution step that runs before your Dart is ever compiled, and the failure surfaces as a build error that names packages you did not add, in versions you did not choose.
FlutterFlow's own guidance on picking a dependency puts platform support first, and it is blunter than most people expect. In the section on choosing the correct package from pub.dev, FlutterFlow's custom code documentation states the requirement plainly: "WEB: It must support Web to run your app in our Run/Test Mode." Not a recommendation. A prerequisite for the editor's own preview to function, which means a package can be perfectly good, perfectly maintained, widely used on mobile, and still unusable to you.
The same page carries a warning people skim past: "The current dependency might depend on other dependencies to work. So make sure you also copy the name and version of all the additional dependencies." Transitive dependencies are where the surprises live.
What FlutterFlow actually does with a pub dependency

You are not editing a pubspec. You are handing a name and a version string to a build system that already has opinions about both.
A dependency reaches a FlutterFlow project by one of two routes. You add it globally under Settings and Integrations, in the Custom Dependencies tab, or you paste the name and version into the Pubspec Dependency panel of the custom code editor beside the widget that needs it. Either way the platform merges your request into a pubspec it owns, alongside the packages FlutterFlow itself depends on for auth, storage, navigation and everything else the generated app does.
That merge is the whole story. Pub's version solver has to find one version of every package that satisfies your constraint, FlutterFlow's constraint, and every transitive constraint underneath both. When no such set exists, version solving fails, and it fails for the project rather than for your widget.
The Libraries documentation says the quiet part directly when describing conflicts between a project and an imported library: "if the project and the library share the same dependency, the version must match exactly to avoid conflicts." Exactly. Not compatibly. That is a much narrower target than the caret ranges you are used to writing by hand.
Why pure-Dart packages survive and native plugins do not

The reliable predictor of whether a package works inside a FlutterFlow custom widget is not its popularity. It is whether it ships native code.
A pure-Dart package is just source. It compiles into the app the same way your widget does, it has no Gradle or CocoaPods surface, and the cloud builder treats it as unremarkable. A plugin is a different animal. It carries Kotlin or Swift, expects entries in the Android and iOS project files, and sometimes requires permissions or capabilities declared at the platform level.
FlutterFlow is explicit about the limit here. Its MethodChannels guide states that the platform "does not allow direct editing of platform-native code (Kotlin, Swift) through its web UI", and the workflow it prescribes for native integrations is to build a Flutter plugin outside FlutterFlow, publish it to a Git repository, and add it to a custom action by Git URL.
Read that as a cost, because it is one. The moment a package needs native code you do not control, the dependency stops being a line in a panel and becomes a repository you maintain, version, and keep compiling against whatever Flutter version the platform is on this month. That is a reasonable trade for a vendor SDK with no alternative. It is an absurd trade for a date picker.
Actually, let me back up. Plenty of plugins do work, because FlutterFlow ships plenty of them itself. The distinction that matters is narrower: a plugin whose native side is already wired into the generated project is fine, and a plugin whose native side you would need to touch is not.
The cloud builder pins dependencies you never chose
Here is the failure mode that catches experienced Flutter developers, because it has no equivalent on a local machine.
The builder carries its own globally pinned dependency set. A package major that resolves cleanly in a local project can be simply unreachable inside FlutterFlow, not because the package is bad but because something below it is held back. A community thread on dependency constraints in the FlutterFlow Cloud Builder describes exactly this shape: a data-sync package's version 2 line requires newer releases of foundational packages than the cloud builder pins, so the upgrade resolves in VS Code and dies in the platform.
The second-order version is worse, because the conflict involves a package you never touched. A FlutterFlow issue opened on 9 September 2026 reports a web deployment failing with a message worth reading twice:
"Because digi_market depends on cloud_functions_web 4.11.2 which depends on web ^1.1.1, web ^1.1.1 is required. So, because digi_market depends on web 1.1.0, version solving failed."
The reporter could not find web 1.1.0 in either the custom or the FlutterFlow dependency list. It was coming from the generated code, introduced by enabling a feature rather than by adding a package. You cannot fix a constraint you cannot see, and you cannot always tell from the error which half of the pubspec is yours.
Which packages are safe inside a FlutterFlow custom widget?
Packages that are pure Dart, declare support for web alongside mobile, and depend on nothing whose major version the platform is already holding down.
Here is how I sort a candidate before it gets anywhere near a design:
| Package shape | What it touches | Behaviour in the cloud build | What to do instead |
|---|---|---|---|
| Pure Dart, no platform code | Nothing outside Dart | Safe. Resolves and compiles like your own widget | Nothing. Use it |
| UI-only package with web support | Widget tree, painting | Safe in practice, and previews correctly in Run/Test Mode | Nothing. Use it |
| Plugin already bundled by FlutterFlow | Native, but wired by the platform | Safe, because the native side already exists in the generated project | Prefer the platform's own integration |
| Plugin needing Kotlin or Swift you would edit | Android and iOS project files | Fails. There is no web UI for native code | Wrap it in your own Flutter plugin, add it by Git URL |
| Package with no web support | Transitive imports pull in dart:io or native-only APIs | Breaks Run/Test Mode even where a mobile build succeeds | Find a web-capable alternative, or gate the feature per platform |
| Package pinned back by the builder | Shared transitive dependencies | Version solving fails for the whole project | Hold at the older major until the platform moves |
The fourth row is the one that has cost me the most. Everything in a marketplace template ships together, including instructions, reference documentation, marketplace imagery and iOS screenshots, so a widget that cannot build is not one broken file. It is a submission that does not go out.
A five-minute dependency check before you design the widget
Run this on the pub.dev page, before a single line of widget code exists:
- Read the platform chips, not the README. pub.dev computes them rather than taking the author's word: its scoring documentation explains that "the platform support will be detected by analyzing the transitive import graph". If Web is missing from that row, FlutterFlow's Run/Test Mode requirement is already unmet.
- Open the Installing tab and count the dependencies. Every transitive package is another constraint the solver has to satisfy against FlutterFlow's own set. Two direct dependencies is a different risk profile from eleven, and the eleven-dependency package is the one that will fail on something three levels down.
- Check whether the repository has an
android/orios/directory. That single glance tells you whether you are adding a package or adopting a plugin. If those folders exist and contain more than a stub, assume the native path and price it accordingly. - Look at the last publish date. FlutterFlow's documentation makes the same point about maintenance, noting that a regularly updated package "is more likely compatible with the latest Dart/Flutter versions and has fewer bugs". A package last touched two years ago is a package that has not met the current Flutter version.
- Weigh the quality score with the platform's own yardstick. FlutterFlow's docs describe Pub Points as telling "the quality of the dependency (out of 130) based on code style, platform support, and maintainability", which is a useful filter precisely because platform support is baked into it.
- Add it to a throwaway project and hit Run Mode before you build anything. Five minutes of waiting beats discovering the conflict after the widget is wired into four screens.
Steps one through three kill most bad candidates. Step six is the only one that is actually proof, and it is the one people skip.
What changed in February
FlutterFlow moved the underlying Flutter version to 3.38.5 on Tuesday 3 February 2026. The upgrade announcement promised "updates to dozens of third-party packages used across FlutterFlow" and warned, in the same breath, that "you may need to make changes to custom code or dependencies". Platform upgrades are not neutral events for custom code. They are the day your pinned versions get renegotiated for you.
Where this leaves the widget you wanted to build
Submission day for a batch of templates, with reference docs written and iOS screenshots captured, is the wrong moment to learn that a dependency will not resolve. That is why the check runs first and the design runs second, which feels backwards until the first time it saves you.
There is a related decision underneath all of this, and it deserves its own answer rather than a paragraph here: whether the widget belongs in FlutterFlow at all, or whether this is the point to drop out of FlutterFlow into pure Flutter. If you are earlier than that and still choosing a platform, the honest version of the trade-off is in my notes on which no-code tools hit a ceiling and where, and the assembled version I actually ship paid mobile apps on is FlutterFlow with Firebase and Stripe.
So before your next custom widget: open the pub.dev page for the dependency you have already half-decided on, and check the platform row. Does Web appear? If it does not, you have just saved yourself a week, and you have not written a line of code yet.
