saropa/saropa_lints
1700+ advanced lint rules for Flutter & Dart. Catches memory leaks, security flaws (OWASP), and runtime crashes that standard linters miss. Optimized for AI coding assistants.
Catch memory leaks, security vulnerabilities, and runtime crashes that standard linters miss.
Developed by Saropa to make the world of Dart & Flutter better.
💬 Have feedback on Saropa Lints? Please share it by opening an issue on GitHub!
VS Code Extension (Recommended)
Install the Saropa Lints VS Code extension for the full experience. Also on Open VSX (Cursor, VSCodium).
The extension is the primary setup and configuration surface:
- Health Score — 0–100 score in the status bar; green/yellow/red bands
- Issues tree — Violations grouped by severity and file, with Error Lens-style inline annotations
- Security Posture — OWASP Top 10 coverage matrix, compliance export
- Triage — Disable noisy rules from the UI; see estimated score impact before acting
- File Risk — Files ranked by violation density; focus on the riskiest first
- Trends — Score progression over time with milestone celebrations
One-click Enable sets up pubspec.yaml, analysis_options, and runs analysis. No terminal commands needed.
Quick Start
Option A — VS Code extension (recommended)
- Install Saropa Lints from the VS Code Marketplace
- Open the Saropa Lints sidebar (checklist icon in the activity bar)
- Click Enable Saropa Lints
The extension adds saropa_lints to your project, configures analysis options, and runs analysis. Use the Config view to change tier, disable rules, and manage platforms/packages. Run "Saropa Lints: Getting Started" from the command palette for a guided tour.
Option B — Tier preset (zero-config, no extension)
dart pub add --dev saropa_lintsAdd one line to your analysis_options.yaml:
include: package:saropa_lints/tiers/recommended.yamlRun dart analyze and issues appear in your IDE and terminal.
Available presets: essential.yaml · recommended.yaml · professional.yaml · comprehensive.yaml · pedantic.yaml
Option C — CLI init (full control, CI/scripting)
dart pub add --dev saropa_lints
dart run saropa_lints:init --tier recommendedNote: The CLI init is headless-only as of v9 — no interactive prompts. For interactive setup, use the VS Code extension.
This updates (or creates) two files:
analysis_options.yaml— theplugins: saropa_lints: diagnostics:section is regenerated with every rule set totrue/falsefor your tier. All other sections are preserved.analysis_options_custom.yaml— your project settings (platforms, analysis output). Created on first run; never overwritten.
Run analysis
dart analyzeIssues appear in your IDE's Problems panel and in the terminal. Saropa Lints runs as a native Dart analyzer plugin.
Available tiers:
essential·recommended·professional·comprehensive·pedantic— see The 5 Tiers for detailsStuck? See Troubleshooting · Upgrading? See Migration guides
How It Works
Dart package VS Code extension
│ │
▼ ▼
analysis_options.yaml ◄─── Enable / Set Tier / Triage
│ │
▼ ▼
dart analyze ◄─── Run Analysis (from UI)
│ │
▼ ▼
violations.json ───► Health Score, Issues, Security,
File Risk, Trends, Inline Annotations
The Dart package provides 2050+ lint rules via the native analyzer plugin. The VS Code extension reads violations.json and provides the UI: Health Score, Issues tree, Security Posture, File Risk, and Config/Triage. Optional Drift Advisor integration shows index suggestions and data-quality anomalies from a running Drift Advisor server in a dedicated sidebar view and in Problems. Both are published together and versioned in sync.
Rule metadata: Each rule can expose optional semantics—RuleType (bug, vulnerability, code smell, security hotspot), tags, MITRE CWE IDs, and RuleStatus (e.g. beta)—for compliance and future quality gates. Defaults are backward compatible; see CONTRIBUTING.md and bugs/discussion/RULE_METADATA_BULK_STATUS.md.
Why Saropa Lints?
Linting vs static analysis
dart analyze checks syntax and style. Static analysis checks behavior.
Your linter catches unused variables and formatting issues. It doesn't catch undisposed controllers, hardcoded credentials, or setState after dispose — because these require understanding what the code does, not just how it's written.
In mature ecosystems, tools like SonarQube, Coverity, and Checkmarx fill this gap. Flutter hasn't had an equivalent — until now.
What it catches
Code that compiles but fails at runtime:
// Memory leak — controller never disposed
final _controller = TextEditingController();
// Crash — setState after widget disposed
await api.fetchData();
setState(() => _data = data); // boom
// State loss — new GlobalKey every build
Widget build(context) {
final key = GlobalKey<FormState>(); // wrong
return Form(key: key, ...);
}Saropa Lints detects these patterns and hundreds more:
- Security — Hardcoded credentials, sensitive data in logs, unsafe deserialization
- Accessibility — Missing semantics, inadequate touch targets, screen reader issues
- Performance — Unnecessary rebuilds, memory leaks, expensive operations in build
- Lifecycle — setState after dispose, missing mounted checks, undisposed resources
Accuracy focused: Rules use proper AST type checking instead of string matching, reducing false positives on variable names like "upstream" or "spinning".
Stop Debugging Known Issues
Saropa Lints specifically targets the error messages developers search for when their app crashes. It statically analyzes and prevents:
- Memory Leaks:
TextEditingController,AnimationController, andStreamSubscriptioncreated but never disposed. - Concurrency Bugs:
BuildContextusage across async gaps and unawaited futures ininitState. - Security Flaws: Hardcoded API keys, insecure HTTP (cleartext), and weak cryptography.
- UI Crashes:
setState() called after dispose(), layout overflow risks, and null assertions on backend data. - State Errors:
Riverpodproviders reading insidebuildorBlocevents added in constructors.
Essential for popular packages
If you use GetX, Riverpod, Provider, Bloc, Isar, Hive, or Firebase, these audits are critical. These libraries are powerful but have patterns that fail silently at runtime:
| Library | Common issues caught | Guide |
|---|---|---|
| GetX | Undisposed controllers, memory leaks from workers, missing super calls | Using with GetX |
| Riverpod | Circular provider deps, ref.read() in build, missing ProviderScope | Using with Riverpod |
| Provider | Provider.of in build causing rebuilds, recreated providers losing state | Using with Provider |
| Bloc | Events in constructor, mutable state, unclosed Blocs, BlocListener in build | Using with Bloc |
| Isar | Enum fields causing data corruption on schema changes; caching Isar streams (runtime crash risk) | Using with Isar |
| Hive | Missing init, unclosed boxes, hardcoded encryption keys, type adapter issues | Using with Hive |
| Firebase | Unbounded queries, missing batch writes, invalid Analytics events, FCM token leaks | Using with Firebase |
Standard linters don't understand these libraries. They see valid Dart code. Saropa Lints has 50+ rules specifically for library-specific anti-patterns that cause crashes, memory leaks, cost overruns, and data corruption in production. Recent update: require_camera_permission_check no longer triggers on non-camera controllers (e.g., IsarStreamController), eliminating a key false positive for Isar users. The new avoid_cached_isar_stream rule (with quick fix) prevents a common Isar runtime error.
Radical Transparency
We build in public. We don't just show you what works; we explicitly document what doesn't work yet.
- ROADMAP.md: Our active backlog. See exactly what rules are coming next and vote on priorities.
- Deferred rules (in ROADMAP.md#part-2-deferred-rules--technical-limitations): The "Hard Problems." Rules we can't implement yet due to technical limitations (cross-file analysis, heuristics). We invite the community to help crack these barriers.
| Marker | Meaning | Example |
|---|---|---|
| 🐙 | Tracked as GitHub issue | Open Issues |
| 💭 | Announcements, Q&A, and Ideas | Discussion: Diagnostic Statistics |
Compliance: EAA & OWASP Security
The European Accessibility Act takes effect June 2025, requiring accessible apps in retail, banking, and travel. GitHub detected 39 million leaked secrets in repositories during 2024.
These aren't edge cases. They're compliance requirements and security basics that standard linters miss.
Comparison vs Standard Tools
Why switch? Saropa Lints covers everything in standard tools plus strict behavioral analysis.
| Feature | flutter_lints |
very_good_analysis |
Saropa Lints |
|---|---|---|---|
| Syntax Checks | ✅ | ✅ | ✅ |
| Strict/Opinionated Style | ❌ | ✅ | ✅ |
| Zero-Config Setup | ✅ | ✅ | ✅ (Tier Presets) |
| Controller Leak Detection | ❌ | ❌ | ✅ (Deep Analysis) |
| Runtime Crash Prevention | ❌ | ❌ | ✅ (Behavioral) |
| Security (OWASP Mapped) | ❌ | ❌ | ✅ (ISO/OWASP) |
| Library Specific (Riverpod/Bloc) | ❌ | ❌ | ✅ (50+ rules) |
| AI-Ready Diagnostics | ❌ | ❌ | ✅ |
| Dependency Scanning | ❌ | ❌ | 🚧 (Coming Soon) |
OWASP Compliance Mapping
Security rules are mapped to OWASP Mobile Top 10 (2024) and OWASP Top 10 (2021) standards. This enables:
- Compliance reporting for security audits
- Risk categorization aligned with industry standards
- Coverage analysis across OWASP categories
| OWASP Mobile | Coverage | OWASP Web | Coverage |
|---|---|---|---|
| M1 Credential Usage | 5+ rules | A01 Broken Access Control | 4+ rules |
| M2 Supply Chain | 2+ rules | A02 Cryptographic Failures | 10+ rules |
| M3 Authentication | 5+ rules | A03 Injection | 6+ rules |
| M4 Input Validation | 6+ rules | A05 Misconfiguration | 4+ rules |
| M5 Communication | 2+ rules | A07 Authentication | 8+ rules |
| M6 Privacy Controls | 5+ rules | A09 Logging Failures | 2+ rules |
| M7 Binary Protections | 2+ rules | ||
| M8 Misconfiguration | 4+ rules | ||
| M9 Data Storage | 7+ rules | ||
| M10 Cryptography | 4+ rules |
Gaps: A06 (Outdated Components) requires dependency scanning tooling.
Rules expose their OWASP mapping programmatically:
// Query a rule's OWASP categories
final rule = AvoidHardcodedCredentialsRule();
print(rule.owasp); // Mobile: M1 | Web: A07Open Source & Community Driven
Unlike "black box" paid tools, Saropa Lints is 100% open source (MIT). You can inspect the logic behind every rule, verify the security checks yourself, and fork it if you disagree.
- No hidden logic: See exactly how we detect vulnerabilities.
- No vendor lock-in: It's standard Dart code.
- Community powered: Rules are often suggested, debated, and refined by the Flutter community, not just a single vendor.
Built for AI
AI coding assistants like Cursor, Windsurf, and Copilot move fast, but they often hallucinate code that compiles yet fails in production. They might forget to dispose a controller, use a deprecated API, or ignore security best practices.
Saropa Lints acts as the guardrails for your AI. By providing immediate, semantic feedback on behavior—not just syntax—it forces the AI to correct its own mistakes in real-time.
Optimized for AI Repair
The tool is also built to fix. Saropa Lints diagnostics are engineered to be "paste-ready," providing deep context and specific failure points. When you copy a problem report directly into your AI tool window, it acts as a perfect prompt—giving the AI exactly the info it needs to refactor the code and resolve the issue immediately, without you needing to explain the context.
Migrating from other tools?
- Migrating from very_good_analysis (also covers
lints,lint,pedantic) - Migrating from DCM (Dart Code Metrics)
- Migrating from solid_lints
- Using with flutter_lints (complementary setup)
Why three options? The extension (Option A) is the recommended interactive experience. Tier presets (Option B) are great for quick, zero-config setup. The CLI init tool (Option C) gives you explicit
true/falsefor every rule, ideal for CI/scripting.
The 5 Tiers
Pick the tier that matches your team's needs. Each tier builds on the previous one.
| Tier | Purpose | Target User | Example Rules |
|---|---|---|---|
| Essential | Prevents crashes, data loss, security breaches, and memory leaks. These are rules where a single violation can cause real harm - app crashes, user data exposed, resources never released. If your app violates these, something bad will happen. | Every project, every team. Non-negotiable baseline. | require_field_dispose (memory leak), avoid_hardcoded_credentials (security breach), check_mounted_after_async (crash), avoid_null_assertion (runtime exception), require_firebase_init_before_use (crash) |
| Recommended | Catches common bugs, basic performance issues, and accessibility fundamentals. These are mistakes that cause real problems but may not immediately crash your app - poor UX, sluggish performance, inaccessible interfaces, silent failures. | Most teams. The sensible default for production apps. | require_semantics_label (accessibility), avoid_expensive_build (performance), require_json_decode_try_catch (error handling), avoid_shrinkwrap_in_scrollview (performance), require_image_error_builder (UX) |
| Professional | Enforces architecture, testability, maintainability, and documentation standards. Code that works but is hard to test, hard to change, or hard to understand. Technical debt that slows teams down over time. | Enterprise teams, long-lived codebases, teams with multiple developers. | avoid_god_class (architecture), require_public_api_documentation (docs), prefer_result_pattern (error handling), require_test_cleanup (testing), avoid_hardcoded_strings_in_ui (i18n) |
| Comprehensive | Stricter patterns, optimization hints, and thorough edge case coverage. Rules that catch subtle issues, enforce consistency, and push toward optimal patterns. Helpful but not critical. | Quality-obsessed teams, libraries/packages, teams that want maximum coverage. | prefer_element_rebuild (subtle perf), prefer_immutable_bloc_state (strict pattern), require_test_documentation (maintainability), prefer_fake_platform (test quality) |
| Pedantic | Everything, including pedantic and highly opinionated rules. Rules that most teams would find excessive but are valuable for greenfield projects or teams that want zero compromise. | New projects starting fresh, teams that want maximum strictness from day one. | prefer_custom_single_child_layout (micro-optimization), prefer_feature_folder_structure (opinionated architecture), avoid_returning_widgets (pedantic) |
Stylistic Rules (Separate Track)
175+ stylistic rules for formatting, ordering, and naming conventions.
Enable stylistic rules individually in your config, or use the VS Code extension's Config/Triage view to enable/disable them with estimated score impact.
For CI/scripting, use --no-stylistic (default) or --stylistic-all to bulk-enable:
dart run saropa_lints:init --tier recommended --stylistic-allConflicting pairs (e.g., prefer_single_quotes vs prefer_double_quotes) must be enabled individually — you choose which style your team prefers.
Stylistic rules are orthogonal to correctness. Your code can be perfectly correct while violating every stylistic rule, or perfectly formatted while crashing on every screen. That's why they're separate.
Configuration template
See example/analysis_options_template.yaml for a complete reference with all 2057+ rules organized by category, tier membership, and examples.
Using a tier
VS Code extension: Use Set Tier from the command palette or click the tier badge in the status bar.
Tier preset (zero-config):
# In analysis_options.yaml — just pick your tier:
include: package:saropa_lints/tiers/recommended.yamlCLI init (full control, CI/scripting):
dart run saropa_lints:init --tier recommended
dart run saropa_lints:init --target /path/to/project
dart run saropa_lints:init --helpAvailable tiers: essential (1), recommended (2), professional (3), comprehensive (4), pedantic (5)
Customizing rules
After generating configuration, customize rules by editing analysis_options.yaml:
plugins:
saropa_lints:
diagnostics:
# The init tool generates explicit true/false for every rule
avoid_hardcoded_strings_in_ui: true # change to false to disable
require_public_api_documentation: false # change to true to enable
# Stylistic rules (enable the ones your team prefers)
prefer_single_quotes: true
prefer_trailing_comma_always: trueRules use standard YAML map format (no - prefix needed).
To change tiers, either switch the include: preset or re-run the init tool:
dart run saropa_lints:init --tier professionalPlatform configuration
The analysis_options_custom.yaml file includes a platforms section that controls which platform-specific rules are active. Only iOS and Android are enabled by default. Enable the platforms your project targets:
# In analysis_options_custom.yaml
platforms:
ios: true # enabled by default
android: true # enabled by default
macos: false # enable if targeting macOS
web: false # enable if targeting web
windows: false # enable if targeting Windows
linux: false # enable if targeting LinuxEach platform has dedicated rules that catch platform-specific issues:
| Platform | Rules | Examples |
|---|---|---|
| iOS | 90+ | Safe area, privacy manifest, App Tracking Transparency, Face ID, HealthKit, keychain |
| Android | 11+ | Runtime permissions, notification channels, PendingIntent flags, cleartext traffic |
| macOS | 15+ | Sandboxing, notarization, hardened runtime, window restoration, entitlements |
| Web | 10+ | CORS handling, platform channels, deferred loading, URL strategy, web renderer |
| Windows | Desktop shared | Menu bar, window close confirmation, native file dialogs, focus indicators |
| Linux | Desktop shared | Same desktop rules as Windows |
Some rules are shared across platform groups:
- Apple rules (iOS + macOS): Apple Sign In, nonce validation
- Desktop rules (macOS + Windows + Linux): Menu bar, window management, keyboard/mouse interaction patterns
When a platform is set to false, its rules move to the disabled section. Shared rules (e.g., Apple Sign In for iOS + macOS) are only disabled when all their platforms are disabled.
User overrides always win — if you force-enable a rule in the overrides section, it stays enabled even if its platform is disabled.
The init tool logs which platforms are disabled and how many rules are affected:
Platforms disabled: web, windows, linux (23 rules affected)
Package configuration
The analysis_options_custom.yaml file includes a packages section that controls which library-specific rules are active. All packages are enabled by default. Disable packages you don't use to reduce noise:
# In analysis_options_custom.yaml
packages:
# State Management
bloc: true
provider: true
riverpod: true
getx: true
# UI & Utilities
flutter_hooks: true
# Data Classes
equatable: true
freezed: true
# Storage & Database
firebase: true
isar: true
hive: true
shared_preferences: true
sqflite: true
# Networking
dio: true
graphql: true
supabase: true
# DI & Services
get_it: true
workmanager: true
# Device & UI
url_launcher: true
geolocator: true
qr_scanner: true
# Gaming
flame: trueSetting a package to false moves all its rules to the disabled section. If you don't use Riverpod, for example, set riverpod: false to remove 24+ Riverpod-specific rules from your analysis.
Rules shared between packages (e.g., database rules shared by Firebase, Isar, Hive, and sqflite) are only disabled when all packages that use them are disabled.
After changing platform or package settings, re-run init to apply:
dart run saropa_lints:initConfig key names and aliases
Rule config keys match the rule name shown in lint messages (the part in [brackets]):
lib/my_file.dart:42 - [prefer_arguments_ordering] Named arguments should be in alphabetical order.
^^^^^^^^^^^^^^^^^^^^^^^^^ This is the config key
To disable this rule: prefer_arguments_ordering: false
Aliases: Some rules support shorter aliases for convenience. For example, prefer_arguments_ordering also accepts arguments_ordering:
plugins:
saropa_lints:
diagnostics:
# Both of these work:
prefer_arguments_ordering: false # canonical name
arguments_ordering: false # aliasAliases are provided for rules where the prefix (enforce_, require_) might be commonly omitted.
Enabling all rules
Use the pedantic tier preset or the init tool to enable all rules:
# Option A: Tier preset
include: package:saropa_lints/tiers/pedantic.yaml
# Option B: Init tool
# dart run saropa_lints:init --tier pedantic --stylistic-allThis is intentional. It forces teams to explicitly review and disable rules they disagree with, ensuring:
- No rule is accidentally overlooked
- Your config becomes a complete record of team style decisions
- Mutually exclusive rules (e.g.,
prefer_single_quotesvsprefer_double_quotes) require explicit choice
If you enable all rules, you will need to disable one rule from each conflicting pair.
Severity levels
Each rule has a fixed severity (ERROR, WARNING, or INFO) defined in the rule itself. Severity cannot be overridden per-project. If a rule's severity doesn't match your needs:
- Use
// ignore: rule_nameto suppress individual occurrences - Disable the rule entirely with
rule_name: false - Open an issue if you think the default severity should change
Baseline for Brownfield Projects
The Problem
You want to adopt saropa_lints on an existing project. You run dart analyze and see:
lib/old_widget.dart:42 - avoid_print
lib/old_widget.dart:87 - no_empty_block
lib/legacy/api.dart:15 - avoid_dynamic
... 500 more violations
That's overwhelming. You can't fix 500 issues before your next sprint. But you also can't ignore linting entirely - new code should be clean.
The Solution: Baseline
The baseline feature records all existing violations and hides them, while still catching violations in new code.
- Old code: Violations hidden (baselined)
- New code: Violations reported normally
This lets you adopt linting today without fixing legacy code first.
Quick Start (One Command)
dart run saropa_lints:baselineThis command:
- Runs analysis to find all current violations
- Creates
saropa_baseline.jsonwith those violations - Updates your
analysis_options.yamlautomatically
Result: Old violations are hidden, new code is still checked.
Three Combinable Baseline Types
| Type | Config | Description | Best For |
|---|---|---|---|
| File-based | baseline.file |
JSON listing specific violations | "Fix nothing yet" |
| Date-based | baseline.date |
Git blame - ignore old code | "Fix gradually by age" |
All three types are combinable - any match suppresses the violation.
Full Configuration
Note: Baseline configuration via YAML is not yet supported. Use the
dart run saropa_lints:baselineCLI command shown above, which generates
the baseline file and updates your config automatically.
The baseline CLI supports these options:
| Option | Description |
|---|---|
--file |
Output file (default: saropa_baseline.json) |
--date |
Ignore code unchanged since this date (uses git blame) |
--paths |
Ignore entire directories (glob patterns) |
--only-impacts |
Only baseline certain severities (e.g., low,medium) |
Path Pattern Examples
| Pattern | Matches |
|---|---|
lib/legacy/ |
All files under lib/legacy/ |
*.g.dart |
All files ending in .g.dart |
lib/**/old_*.dart |
Files like lib/foo/old_widget.dart |
Priority Filtering
Use only_impacts to baseline only certain severity levels while still seeing critical issues:
baseline:
file: "saropa_baseline.json"
only_impacts: [low, medium, opinionated] # Still see critical and highCleaning Up Over Time
As you fix violations, update the baseline to remove fixed items:
dart run saropa_lints:baseline --updateOutput shows what was fixed:
Baseline Update Summary:
Previous: 150 violations
Current: 120 violations
Fixed: 30 violations removed!
CLI Reference
dart run saropa_lints:baseline # Generate new baseline
dart run saropa_lints:baseline --update # Refresh, remove fixed violations
dart run saropa_lints:baseline --dry-run # Preview without changes
dart run saropa_lints:baseline --skip-config # Don't update analysis_options.yaml
dart run saropa_lints:baseline -o custom.json # Custom output path
dart run saropa_lints:baseline ./my_project # Run on specific directory
dart run saropa_lints:baseline --help # See all optionsCross-file analysis CLI
Find unused files and circular import chains (no IDE integration; CLI only):
dart run saropa_lints:cross_file unused-files # Files not imported by any other file
dart run saropa_lints:cross_file circular-deps # Circular import chains
dart run saropa_lints:cross_file import-stats # Import graph statistics
dart run saropa_lints:cross_file report # HTML report (default: reports/)
dart run saropa_lints:cross_file --help
# JSON output to file (e.g. for CI or tooling)
dart run saropa_lints:cross_file unused-files --output json > unused.json
# Baseline: suppress known issues, fail only on new violations
dart run saropa_lints:cross_file unused-files --baseline cross_file_baseline.json
dart run saropa_lints:cross_file unused-files --update-baselineOptions: --path <dir>, --output text|json, --output-dir <path> (for report), --baseline <file>, --update-baseline, --exclude <glob> (reserved). Exit codes: 0 = no issues, 1 = issues found, 2 = error. Example GitHub Actions workflow for CI. See ROADMAP Part 3.
Standalone Scanner
Run saropa_lints rules against any Dart project — even one that doesn't have saropa_lints as a dependency. Useful for evaluating a project before adopting the package, or for scanning the saropa_lints codebase itself.
The scanner reads the project's analysis_options.yaml (generated by init) to determine which rules to run, unless you pass --tier. Two steps:
# 1. Configure rules (once)
dart run saropa_lints init --target /path/to/project --tier recommended
# 2. Scan
dart run saropa_lints scan /path/to/projectCLI options: --tier <name> (essential | recommended | professional | comprehensive | pedantic) overrides the project config for that run. --files <path>... scans only the listed Dart files; --files-from-stdin reads one path per line from stdin. --format json writes machine-readable JSON to stdout (no report file). Results are otherwise written to reports/<date>/<timestamp>_scan_report.log with a compact summary printed to terminal.
Programmatic scan: Import package:saropa_lints/scan.dart to run scans from code (e.g. from another package or script) without invoking the CLI. The public API includes ScanRunner, ScanConfig, ScanDiagnostic, loadScanConfig, scanDiagnosticsToJson, and scanDiagnosticsToJsonString. Example:
import 'package:saropa_lints/scan.dart';
final runner = ScanRunner(
targetPath: '/path/to/project',
tier: 'recommended', // optional: override config with a tier
dartFiles: ['lib/main.dart'], // optional: scan only these files
messageSink: (msg) => log(msg), // optional: redirect or suppress output
);
final diagnostics = runner.run();
if (diagnostics != null) {
final json = scanDiagnosticsToJsonString(diagnostics);
// ...
}JSON output (from --format json or scanDiagnosticsToJson) includes version, diagnostics (each with filePath, line, column, ruleName, severity, problemMessage, correctionMessage?), and summary (totalCount, byFile, byRule).
Rule Categories
| Category | Description |
|---|---|
| Flutter Widgets | Lifecycle, setState, keys, performance |
| Modern Dart 3.0+ | Class modifiers, patterns, records, when guards |
| Modern Flutter | TapRegion, OverlayPortal, SearchAnchor, CarouselView |
| State Management | Provider, Riverpod, Bloc patterns |
| Performance | Build optimization, memory, caching |
| Security | Credentials, encryption, input validation — OWASP mapped |
| Accessibility | Screen readers, touch targets, semantics |
| Testing | Assertions, mocking, flaky test prevention |
| Architecture | Clean architecture, DI, SOLID principles |
| Error Handling | Exceptions, logging, recovery |
| Async | Futures, Streams, cancellation |
| API & Network | Timeouts, retries, caching |
| Internationalization | Localization, RTL, plurals |
| Documentation | Public API, examples, deprecation |
Stylistic Rules
175+ rules for team preferences — not included in any correctness tier. Enable individually in your config, via the VS Code extension's Config/Triage view, or use --stylistic-all to bulk-enable.
Examples: prefer_relative_imports, prefer_single_quotes, prefer_arrow_functions, prefer_trailing_comma_always, prefer_for_in, prefer_boolean_prefixes_for_params
See README_STYLISTIC.md for the full list with examples, pros/cons, and quick fixes.
Performance
Saropa Lints runs as a native Dart analyzer plugin — no separate process needed. The tier system helps manage analysis scope:
- Rules set to
falseare not loaded - Start with
essentialorrecommended - Upgrade tiers as you fix warnings
# GOOD: Start with recommended tier
dart run saropa_lints:init --tier recommended
# CAUTION: Enabling everything on a legacy codebase may show thousands of warnings
dart run saropa_lints:init --tier pedanticPerformance Tip: Use Lower Tiers During Development
For faster iteration during development:
- Use
essentialtier locally — catches critical bugs with fewer rules - Use
professionalor higher in CI — thorough checking where speed matters less - Upgrade tiers gradually — fix warnings before enabling more rules
The tier you choose has a direct impact on analysis speed:
essential: ~300 rules → fastest (memory leaks, security, crashes)recommended: ~900 rules → moderate (+ accessibility, performance)professional: ~1700 rules → slower (+ architecture, documentation)comprehensive/pedantic: 1854+ rules → slowest (everything)
Adoption Strategy
Static analysis doesn't create problems — it reveals ones that already exist. The tiered system lets you start at any level and progress at your own pace. Findings are for your workflow. You control what you address and when.
New Projects
Start with professional or comprehensive. Fix issues as you write code.
Existing Projects
- Enable
essential. Fix critical issues first. - Move to
recommended. Fix warnings as you touch files. - Enable higher tiers when the noise is manageable.
Suppressing Warnings
When a rule doesn't apply to specific code:
// ignore: avoid_hardcoded_strings_in_ui
const debugText = 'DEBUG MODE';
// For entire files:
// ignore_for_file: avoid_print_in_productionAlways add a comment explaining why you're suppressing.
Automatic File Skipping
Rules automatically skip files that can't be manually fixed:
| File Pattern | Skipped By Default |
|---|---|
*.g.dart, *.freezed.dart, *.gen.dart |
Yes (generated code) |
*_fixture.dart, fixture/**, fixtures/** |
Yes (test fixtures) |
*_test.dart, test/** |
Yes (override with testRelevance) |
example/** |
No (override with skipExampleFiles) |
Test files are skipped by default because most production-focused rules generate noise in test code. Override testRelevance to change behavior per rule:
TestRelevance.never— skip test files (default)TestRelevance.always— run on all files including testsTestRelevance.testOnly— run only on test files
Limitations
- Scope: Saropa Lints runs as a native analyzer plugin on the package where it's configured. For multi-package workspaces, add
saropa_lintsto each package'sanalysis_options.yaml. - File types: Only Dart source files (
.dart) are analyzed. Non-Dart assets (JSON, XML, YAML, scripts, etc.) are out of scope.
Running the Linter
Command line:
dart analyzeSaropa Lints runs as a native Dart analyzer plugin. Issues appear automatically in your IDE's Problems panel and in dart analyze output.
When analysis runs with reporting enabled, the plugin also writes a combined log under reports/<date>/ (filename contains _saropa_lint_report). That file includes FILE IMPORTANCE (fan-in × layer), FIX PRIORITY (violations sorted by impact × importance), and PROJECT STRUCTURE (import tree), built from import data collected during analysis.
Impact Report
Run lints with results grouped by business impact:
dart run saropa_lints:impact_reportOutput shows critical issues first, with actionable guidance:
--- CRITICAL (2) ---
lib/main.dart:45 - avoid_hardcoded_credentials
lib/auth.dart:23 - require_dispose
--- HIGH (5) ---
lib/widget.dart:89 - avoid_icon_buttons_without_tooltip
...
Impact Summary
==============
CRITICAL: 2 (fix immediately!)
HIGH: 5 (address soon)
MEDIUM: 12 (tech debt)
LOW: 34 (style)
Total: 53 issues
Impact levels:
critical: Each occurrence is serious — even 1-2 is unacceptable (memory leaks, security)high: 10+ requires action (accessibility, performance anti-patterns)medium: 100+ indicates tech debt (error handling, complexity)low: Large counts acceptable (style, naming conventions)
Exit code equals the number of critical issues (capped at 125), making it CI-friendly.
IDE Integration
Saropa Lints uses the native Dart analyzer plugin system. Issues appear directly in your IDE's Problems panel — no extra setup required.
If you don't see warnings:
- Run
dart pub get(orflutter pub get) - Restart your IDE (VS Code:
Ctrl+Shift+P→ "Developer: Reload Window") - Check View → Output → Dart Analysis Server for errors
Troubleshooting
Can't use saropa_lints v7 in my Flutter project
I'm new and completely lost
Start here:
-
Install: Add to your
pubspec.yamldev_dependencies:dev_dependencies: saropa_lints: ^9.0.0
-
Configure: Add to your
analysis_options.yaml:include: package:saropa_lints/tiers/recommended.yaml
-
Get dependencies:
dart pub get
-
Reload VS Code:
- Press
Ctrl+Shift+P - Type "reload"
- Click "Developer: Reload Window"
- Press
-
Check: Look at the PROBLEMS panel (View → Problems), or run
dart analyze
Still not working? See the sections below.
IDE doesn't show lint warnings
Quick Fix (works 90% of the time):
- Press
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - Type "reload"
- Click "Developer: Reload Window"
- Wait for analysis to complete
If that doesn't work:
- Clear the cache: Delete the
.dart_toolfolder and rundart pub get - Reload VS Code again (steps above)
- Check View → Output → Dart Analysis Server for errors
- Verify configuration is correct (see "Configuration not working" below)
Alternative (command line):
Run dart analyze in your terminal to see all issues immediately.
Configuration not working (not enough rules loading)
Problem: You only get a few rules instead of the full set for your chosen tier.
Solution: Use the CLI tool to generate explicit configuration:
# Generate config for comprehensive tier
dart run saropa_lints:init --tier comprehensive
# Or for all rules (pedantic tier)
dart run saropa_lints:init --tier pedanticThis generates analysis_options.yaml with explicit rule_name: true for every enabled rule.
Verify it worked: Run dart analyze and check the output.
Too many warnings! What do I do?
This is normal when first installing. You'll see hundreds or thousands of warnings.
Option 1: Start smaller (recommended for existing projects)
# Start with essential tier (~300 critical rules)
dart run saropa_lints:init --tier essentialOption 2: Use baseline (for brownfield projects)
Generate a baseline to suppress existing issues and only catch new violations:
dart run saropa_lints:baselineOption 3: Disable noisy rules
Edit your analysis_options.yaml and set specific rules to false:
plugins:
saropa_lints:
diagnostics:
prefer_double_quotes: false # disabled
prefer_trailing_comma_always: false
no_magic_number: falseOption 4: Use quick fixes
Many rules have automatic fixes:
- Hover over the warning
- Click "Quick Fix" or press
Ctrl+. - Select "Fix all in file" to fix all instances at once
- Or run
dart fix --applyfrom the command line
Don't stress about fixing everything immediately. Pick one category (like accessibility or memory leaks) and fix those first.
Out of Memory errors
If you see errors like:
../../runtime/vm/zone.cc: 96: error: Out of memory.
Solution 1: Clear the pub cache (most effective)
dart pub cache clean
dart pub getSolution 2: Increase Dart heap size (PowerShell)
$env:DART_VM_OPTIONS="--old_gen_heap_size=4096"
dart analyzeSolution 3: Delete local build artifacts
# Windows
rmdir /s /q .dart_tool && dart pub get
# macOS/Linux
rm -rf .dart_tool && dart pub getNative crashes (Windows)
If you see native crashes with error codes like ExceptionCode=-1073741819:
# Windows
rmdir /s /q .dart_tool && flutter pub get
# macOS/Linux
rm -rf .dart_tool && flutter pub getThen run dart analyze again.
Frequently Asked Questions
Q: Does this replace flutter_lints?
A: You can run them side-by-side, but Saropa Lints covers everything in flutter_lints plus 2000+ additional behavioral and security checks. Most teams replace flutter_lints entirely. With v5, you no longer need custom_lint either — just saropa_lints in your dev_dependencies.
Q: Will this slow down my CI/CD pipeline?
A: Saropa Lints runs as a native analyzer plugin, integrated directly into dart analyze. The Tier System allows you to balance speed and strictness. The essential tier is designed to be fast for CI environments.
Q: Can I use this with existing legacy projects?
A: Yes! Use the Baseline feature (dart run saropa_lints:baseline) to suppress existing issues instantly. This lets you enforce quality on new code without having to fix 500+ legacy errors first.
Q: I'm upgrading from v4 — what changed?
A: v5 uses the native Dart analyzer plugin system instead of custom_lint. Remove custom_lint from your dependencies, replace custom_lint: rules: with plugins: saropa_lints: diagnostics: in your config (or just use a tier preset), and run dart analyze instead of dart run custom_lint. The init tool handles the config migration automatically.
Contributing
We are building the industry standard together.
We don't have all the answers. We believe great tools are forged by many hands, and if you've shipped production Flutter apps, we want your opinions.
If you think a rule is:
- Wrong - tell us why, we'll fix it or remove it
- Too strict - maybe it belongs in a higher tier
- Too lenient - maybe it should be stricter or have options
- Missing - propose it, or better yet, implement it
Want to learn AST analysis? We mentor contributors. Pick a "Good First Issue" and we'll guide you through writing your first linter.
How to contribute
See CONTRIBUTING.md for detailed guidelines.
Adding a new rule:
- Create rule in appropriate
lib/src/rules/*.dartfile - Register in
lib/src/rules/all_rules.dart - Add to the appropriate tier in
lib/src/tiers.dart - Add tests in
test/ - Update CHANGELOG.md
Reporting issues:
- Include a minimal code sample that triggers (or should trigger) the rule
- Explain what you expected vs what happened
- If you disagree with a rule's premise, say so directly
Discussing rules
Not sure if something is a bug or a design decision? Open a discussion issue. We're happy to explain our reasoning and change our minds when presented with good arguments.
Professional Services
Optional paid services for teams that want hands-on help. See PROFESSIONAL_SERVICES.md for details.
| Service | Description |
|---|---|
| New Projects | Development scoped to your stage — MVP, Production, or Enterprise |
| Upgrade | Move existing projects to higher tiers as they grow |
| Audit | Assess codebases you inherited; remediation quoted separately |
| Custom Rules | Rules specific to your architecture and compliance requirements |
Contact: saropa.com | services@saropa.com
Documentation
| Document | Description |
|---|---|
| README_STYLISTIC.md | 175+ optional stylistic rules with examples |
| PERFORMANCE.md | Performance optimization guide and profiling |
| ROADMAP.md | Planned rules and project direction |
| ROADMAP.md#part-2 | Deferred rules (cross-file, heuristic) |
| CONTRIBUTING.md | How to contribute rules and report issues |
| CHANGELOG.md | Version history and release notes |
| SECURITY.md | Security policy and reporting vulnerabilities |
| PROFESSIONAL_SERVICES.md | Professional services and custom rules |
Package Integration Guides
We provide specialized lint rules for popular Flutter packages. These catch library-specific anti-patterns that standard linters miss.
| Category | Package | Guide |
|---|---|---|
| State Management | Riverpod | Using with Riverpod |
| Bloc | Using with Bloc | |
| Provider | Using with Provider | |
| GetX | Using with GetX | |
| Databases | Isar | Using with Isar |
| Hive | Using with Hive | |
| Backend Services | Firebase | Using with Firebase |
| Platform | iOS/macOS | Apple Platform Rules |
For Package Authors
Want lint rules for your package? We'd love to collaborate with package maintainers to add rules that catch common gotchas and enforce best practices for your library.
Benefits:
- Help users avoid common mistakes with your package
- Reduce support burden from preventable issues
- Improve developer experience with your library
Contact us via CONTRIBUTING.md or open an issue to discuss adding rules for your package.
Badge
Show off your code quality
Prove that your code is secure, memory-safe, and accessible. Add the Saropa Lints style badge to your README to indicate you follow strict behavioral standards.
[](https://pub.dev/packages/saropa_lints)License
MIT - see LICENSE. Use it however you like.
Built with care by the Flutter community. Questions? Ideas? We'd love to hear from you.
pub.dev | GitHub | Issues | Saropa
About This Project
"The bitterness of poor quality remains long after the sweetness of meeting the schedule has been forgotten." — Karl Wiegers
"Quality is not an act, it is a habit." — Aristotle
saropa_lints is a comprehensive static analysis package for Flutter and Dart applications. With 2057+ lint rules organized into 5 progressive tiers (and more planned), it catches memory leaks, security vulnerabilities, accessibility violations, and runtime crashes that standard linters miss. Whether you're building a startup MVP or enterprise software, saropa_lints helps you ship more stable, secure, and accessible apps.
Keywords: Flutter linter, Dart static analysis, Flutter code quality, memory leak detection, security scanning, accessibility testing, WCAG compliance, European Accessibility Act, Flutter best practices, Dart analyzer plugin, code review automation, CI/CD linting, Flutter enterprise tools
Hashtags: #Flutter #Dart #StaticAnalysis #CodeQuality #FlutterDev #DartLang #Linting #DevTools #OpenSource #Accessibility #Security #BestPractices
Sources
-
Dart Analyzer — Dart's static analysis engine
https://dart.dev/tools/analysis -
analysis_server_plugin — Native Dart analyzer plugin framework
https://pub.dev/packages/analysis_server_plugin -
Flutter Accessibility — Flutter accessibility documentation
https://docs.flutter.dev/ui/accessibility-and-internationalization/accessibility -
WCAG 2.1 Guidelines — Web Content Accessibility Guidelines
https://www.w3.org/WAI/standards-guidelines/wcag/ -
European Accessibility Act — EU accessibility legislation effective June 2025
https://accessible-eu-centre.ec.europa.eu/content-corner/news/eaa-comes-effect-june-2025-are-you-ready-2025-01-31_en -
GitHub Secret Scanning — Leaked credentials detection report
https://github.blog/security/application-security/next-evolution-github-advanced-security/ -
OWASP Top 10 — Application security vulnerabilities
https://owasp.org/www-project-top-ten/ -
SonarQube — Static analysis platform
https://www.sonarsource.com/products/sonarqube/ -
Effective Dart — Official Dart style guide
https://dart.dev/effective-dart -
Flutter Performance — Performance best practices
https://docs.flutter.dev/perf




