avoid_long_functions
This rule flags a function body longer than the configured line budget.
Why use this rule
Section titled “Why use this rule”A long function is not wrong, but it is where several responsibilities usually end up sharing one scope and one set of locals. Enforcing a budget in the analyzer puts the signal at the point of writing, where splitting is cheap, rather than in a CI script that reports it after the fact — which is what makes it a genuine replacement for a check_file_length.sh-style gate.
Lines are counted from the body’s braces, so the signature and any doc comment do not count against it.
This rule is in the pedantic preset. A budget is a house style, and the default of 50 is stricter than many codebases run: measured against a production Flutter app it reported 187 functions, median 98 lines — all genuinely long, none of them a bug. Override the budget when your project needs a different limit.
Test files usually want an exclusion
Section titled “Test files usually want an exclusion”A test main() legitimately runs to hundreds of lines, since every test(...) is one more statement in the same body. Scope the rule rather than raising the budget for everything:
rules: avoid_long_functions: exclude: - test/**The examples below use a small budget so the difference fits on a page. The default is 50.
With max_lines: 10, this body is 16 lines, and it validates, prices,
persists and notifies in one scope:
void handleOrder(Order order) { if (order.lines.isEmpty) { throw ArgumentError.value(order, 'order', 'has no lines'); } if (order.customerId.isEmpty) { throw ArgumentError.value(order, 'order', 'has no customer'); }
var total = 0; for (final line in order.lines) { total += line.unitPrice * line.quantity; } order.total = total - order.discount;
orders[order.id] = order; outbox.add('order-placed:${order.id}'); outbox.add('invoice-due:${order.id}');}Each step is named, and each can be read and tested on its own:
void handleOrder(Order order) { _validate(order); order.total = _priceOf(order); _persist(order); _notify(order);}
void _validate(Order order) { if (order.lines.isEmpty) { throw ArgumentError.value(order, 'order', 'has no lines'); } if (order.customerId.isEmpty) { throw ArgumentError.value(order, 'order', 'has no customer'); }}
int _priceOf(Order order) { var total = 0; for (final line in order.lines) { total += line.unitPrice * line.quantity; } return total - order.discount;}
void _persist(Order order) => orders[order.id] = order;
void _notify(Order order) { outbox.add('order-placed:${order.id}'); outbox.add('invoice-due:${order.id}');}Enabling this rule
Section titled “Enabling this rule”This rule is in the pedantic preset, so it is enabled by preset: pedantic or by name:
rules: avoid_long_functions: enabled: trueOptions
Section titled “Options”many_lints: rules: avoid_long_functions: max_lines: 80rules: avoid_long_functions: max_lines: 80| Option | Type | Default | Description |
|---|---|---|---|
max_lines |
int | 50 |
The longest body allowed, counted between the braces |
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: avoid_long_functions: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_complex_conditions— Keep boolean conditions within an operand budget.avoid_deep_nesting— Keep control flow within a nesting budget.avoid_high_cyclomatic_complexity— Keep a function within a complexity budget.max_statements— Keep a function within a statement budget.