DEV Community

Cover image for Write your Flutter lint rules in YAML
Noa Tubić
Noa Tubić

Posted on Originally published at Medium

Write your Flutter lint rules in YAML

Every codebase has house rules. Use the design tokens, not Colors.grey. Don't let domain/ import presentation/. Never call ref.watch from a button handler.

They live in a style guide or a wiki page, and nothing checks them. So they drift. The worst kind is a design token typo: 'Text/bdy' instead of 'Text/body'. Token lookups usually fall back to a default color, so nothing fails. The diff looks fine in review, and a pink widget ships.

The Dart analyzer can't express rules like these. The usual answer is a custom analyzer plugin: a second package, Dart code per rule, and upkeep every time the analyzer changes. For a handful of project conventions, that felt like too much. So I wrote house_rules, where a rule is a few lines of YAML.

What it does

rules:
  avoid_palette_colors:
    severity: error
    exclude: [lib/theme/**]
    palette: Colors
    allowed: [transparent, white]
Enter fullscreen mode Exit fullscreen mode

That's the whole rule. It ships with ten of them, all configured from one house_rules.yaml:

  • known_design_tokens: every token you look up by string must exist
  • layer_boundaries: which folders may import which
  • no_watch_in_callback: no ref.watch inside handlers and listeners
  • no_widget_returning_function and no_method_in_build
  • avoid_palette_colors, avoid_raw_colors, avoid_inline_text_styles and magic_spacing for design system discipline
  • unjustified_ignore: a suppression comment has to say why

Try it

dart pub global activate house_rules
house_rules init              # writes a starter house_rules.yaml
house_rules                   # see what it finds
house_rules --update-baseline # accept what is already there
Enter fullscreen mode Exit fullscreen mode

After the baseline, only new problems fail. It needs Dart 3.11 or newer.

What a finding looks like

This is the output on the example project in the repo:

lib/features/cart/presentation/widgets/cart_row.dart
  12:12    ERROR   avoid_palette_colors
           `Colors.grey` bypasses the design tokens

  21:48    ERROR   known_design_tokens
           'Text/bdy' is not a defined design token
           did you mean:
             'Text/body'
             'Text/headline'
Enter fullscreen mode Exit fullscreen mode

Each finding says why the rule exists and, where it can, what you probably meant. known_design_tokens reads your token map, so it knows the real names and catches the typo before it ships.

Fast enough to run on every save

It only parses files and never resolves types. That is a real limit, but it keeps a scan cheap. On a 2,937-file Flutter app with all ten rules, the compiled binary checks the whole project in 0.285 seconds, and a single file in 0.08 seconds.

That makes it practical as an editor or agent hook:

house_rules --hook "$CHANGED_FILE"
Enter fullscreen mode Exit fullscreen mode

It stays silent when the file is clean and exits with code 2 when it isn't. If the linter itself crashes, it exits 0. A broken linter should never be the reason someone can't commit.

Adopting it on an old codebase

Turning on a new rule in an existing project usually means hundreds of findings on day one. --update-baseline records them, so CI stays green and only new violations fail.

The baseline is keyed by a hash of the offending code, not by line numbers, so it survives dart format and unrelated edits. For rules where every finding is a real bug, set baseline: false and they can never be hidden.

There are also Markdown, HTML, JSON and GitLab Code Quality reports, and a --check-docs mode that fails when your written guidelines and your config disagree.

Try it on your project

Run house_rules init, keep the two or three rules you already agree on, and baseline the rest. You can tighten it later. The code and the docs for every rule are here:

GitHub logo NoaTubic / house_rules

Write your project's lint rules in YAML instead of building a custom_lint plugin. Design tokens, layering, widget and state-management rules.

house_rules

Write your project's lint rules in YAML.

Every codebase has house rules. Use the design tokens, not Colors.grey Don't let domain/ import presentation/. Never call ref.watch from a button handler. They end up in a style guide, a wiki page, a CONTRIBUTING.md — and nothing checks any of them, so they drift.

The Dart analyzer can't express rules like these. The usual answer is to write a custom_lint plugin, which means a second package, Dart code per rule, and a plugin that has to be kept in step with the analyzer. For a handful of project conventions, that is a lot of ceremony.

house_rules gives you the same enforcement as four lines of YAML:

rules:
  avoid_palette_colors:
    severity: error
    exclude: [lib/theme/**]
    palette: Colors
    allowed: [transparent, white]
Enter fullscreen mode Exit fullscreen mode
lib/features/cart/widget.dart
  88:14  ERROR  avoid_palette_colors
         `Colors.grey` bypasses the design tokens
         A literal palette colour will not follow
…

https://pub.dev/packages/house_rules

Feedback and issues are welcome on GitHub.

Top comments (0)