Flutter Custom Lint Rules: Enforce Conventions for AI and Human Code
Introduction
AI-assisted coding — whether with Copilot, Cursor, or Claude — can speed up development a lot. But it has a downside we all run into: it often generates code that is almost right.
It might use APIs we’ve banned, skip parameters we require (like RouteSettings), or ignore project conventions. Fixing these by hand is tedious and easy to miss in review.
That’s exactly why custom lint rules are more valuable than ever: they turn your team’s rules and conventions into something the toolchain enforces automatically, so AI-generated (and human-written) code is checked the same way.
Why Custom Lint Matters Now
When you paste a snippet or accept an AI suggestion, the code often:
- Uses APIs your team has decided to avoid (e.g.
ScaffoldMessengerin favour of a centralised service). - Omits parameters you’ve standardised on (e.g.
routeSettingson every dialog and sheet for observability and testing).
Catching this only in code review is unreliable. Custom lint runs on every file the analyzer sees, so violations show up in the IDE and in CI. That way, both AI output and human code are held to the same rules.
Setup
In this article we’ll look at how to enforce API restrictions and project conventions in Flutter using the custom_lint package.
📁 File: pubspec.yaml
dev_dependencies:
custom_lint: ^0.8.1
custom_lint_rules:
path: packages/custom_lint_rules
📁 File: analysis_options.yaml
analyzer:
plugins:
- custom_lint
custom_lint:
rules:
- no_scaffold_messenger
- require_route_settings
Run flutter pub get. Lints appear in the IDE and when you run:
dart run custom_lint
Example: Correct vs Incorrect
Correct (no violations)
- No
ScaffoldMessenger; use your own service or route-based feedback. showDialog/showModalBottomSheetwithrouteSettings: RouteSettings(name: '...').MaterialPageRoute(..., settings: RouteSettings(name: '...'), builder: ...).Navigator.pushNamed(context, '/detail')is allowed as-is (no routeSettings in the API).
Incorrect (reported by the rules)
ScaffoldMessenger.of(context).showSnackBar(...)→ no_scaffold_messenger.showDialog(context: context, builder: ...)withoutrouteSettings→ require_route_settings.MaterialPageRoute(builder: ...)withoutsettings→ require_route_settings.
Conclusion
AI will keep suggesting code that doesn’t quite match your conventions. Custom lint turns those conventions into something the analyzer enforces for every edit — whether it comes from you or from the model. Starting with a couple of rules (like banning an API and requiring RouteSettings) is enough to get immediate value and a pattern you can reuse for more rules later.
Thank you for reading, I hope it is helpful. If you have any questions, feel free to ask on LinkedIn.
You can access the source code of the application from the link below: