Summary
SwiftLint is running 88 "invisible" default-ON rules not explicitly mentioned in our config. Switching from disabled_rules to only_rules yields a 16x performance improvement (1.27s → 0.08s).
Benchmarks
| Config |
Time |
Rules |
Current (disabled_rules) |
1.27s |
107 rules |
only_rules (no SourceKit) |
0.08s |
20 rules |
swiftlintcustom-smart |
0.07s |
14 rules |
Root Cause
SwiftLint loads ALL ~200 rules, then applies disabled_rules filter. With only_rules, it only loads what you specify.
Additionally, many enabled rules use SourceKit (compiler queries), which are slow:
file_length
statement_position
trailing_whitespace
vertical_whitespace
unused_import (analyzer)
Invisible Default Rules (88 total)
These rules are running but not mentioned in our config:
Formatting/Style (SwiftFormat handles these)
closing_brace, colon, comma, leading_whitespace
operator_whitespace, return_arrow_whitespace
statement_position, trailing_newline, trailing_semicolon
trailing_whitespace, vertical_whitespace, vertical_parameter_alignment
Redundancy Detection (useful, keep)
redundant_discardable_let, redundant_objc_attribute
redundant_optional_initialization, redundant_set_access_control
redundant_string_enum_value, redundant_void_return, redundant_sendable
Legacy Code Detection (useful, keep)
legacy_cggeometry_functions, legacy_constant, legacy_constructor
legacy_hashing, legacy_random, legacy_nsgeometry_functions
Safety/Bugs (useful, keep)
force_cast, force_try, duplicate_enum_cases, duplicate_imports
unused_closure_parameter, unused_optional_binding, unused_enumerated
duplicate_conditions, duplicated_key_in_dictionary_literal
Low Value / Noise (consider dropping)
block_based_kvo, class_delegate_protocol, xctfail_message
valid_ibinspectable, private_unit_test, nsobject_prefer_isequal
inclusive_language, orphaned_doc_comment
Metrics (configured but using SourceKit)
cyclomatic_complexity, file_length, function_parameter_count
large_tuple, nesting, type_body_length, type_name
Recommendations
1. Create only_rules config
Replace disabled_rules approach with explicit allowlist:
only_rules:
# Safety
- force_cast
- force_try
- duplicate_imports
- duplicate_enum_cases
- unused_closure_parameter
# Redundancy
- redundant_discardable_let
- redundant_optional_initialization
- redundant_void_return
# Legacy
- legacy_constructor
- legacy_random
# Metrics (non-SourceKit)
- cyclomatic_complexity
- nesting
# Opt-ins we already use
- empty_count
- empty_string
- first_where
- last_where
- toggle_bool
- implicit_return
2. Remove rules SwiftFormat handles
These are redundant with SwiftFormat:
- All spacing rules (
colon, comma, operator_whitespace, etc.)
trailing_whitespace, trailing_newline
vertical_whitespace
3. Consider two configs
Configs/
├── shared-swiftlint.yml # Full config for CI
└── shared-swiftlint-fast.yml # Fast config for local dev
Add --fast flag to swiftlint-smart for quick iterations.
4. Move SourceKit rules to CI-only
These are valuable but slow:
unused_import (analyzer rule)
file_length
Run them in CI, not on every save.
Impact
- 16x faster local linting
- Explicit control over what runs
- No duplicate checks with SwiftFormat
- Same coverage for meaningful rules
Related
- Custom rules already achieve 0.07s by being focused and avoiding SourceKit
- SwiftFormat handles most style/formatting rules better
Summary
SwiftLint is running 88 "invisible" default-ON rules not explicitly mentioned in our config. Switching from
disabled_rulestoonly_rulesyields a 16x performance improvement (1.27s → 0.08s).Benchmarks
disabled_rules)only_rules(no SourceKit)swiftlintcustom-smartRoot Cause
SwiftLint loads ALL ~200 rules, then applies
disabled_rulesfilter. Withonly_rules, it only loads what you specify.Additionally, many enabled rules use SourceKit (compiler queries), which are slow:
file_lengthstatement_positiontrailing_whitespacevertical_whitespaceunused_import(analyzer)Invisible Default Rules (88 total)
These rules are running but not mentioned in our config:
Formatting/Style (SwiftFormat handles these)
closing_brace,colon,comma,leading_whitespaceoperator_whitespace,return_arrow_whitespacestatement_position,trailing_newline,trailing_semicolontrailing_whitespace,vertical_whitespace,vertical_parameter_alignmentRedundancy Detection (useful, keep)
redundant_discardable_let,redundant_objc_attributeredundant_optional_initialization,redundant_set_access_controlredundant_string_enum_value,redundant_void_return,redundant_sendableLegacy Code Detection (useful, keep)
legacy_cggeometry_functions,legacy_constant,legacy_constructorlegacy_hashing,legacy_random,legacy_nsgeometry_functionsSafety/Bugs (useful, keep)
force_cast,force_try,duplicate_enum_cases,duplicate_importsunused_closure_parameter,unused_optional_binding,unused_enumeratedduplicate_conditions,duplicated_key_in_dictionary_literalLow Value / Noise (consider dropping)
block_based_kvo,class_delegate_protocol,xctfail_messagevalid_ibinspectable,private_unit_test,nsobject_prefer_isequalinclusive_language,orphaned_doc_commentMetrics (configured but using SourceKit)
cyclomatic_complexity,file_length,function_parameter_countlarge_tuple,nesting,type_body_length,type_nameRecommendations
1. Create
only_rulesconfigReplace
disabled_rulesapproach with explicit allowlist:2. Remove rules SwiftFormat handles
These are redundant with SwiftFormat:
colon,comma,operator_whitespace, etc.)trailing_whitespace,trailing_newlinevertical_whitespace3. Consider two configs
Add
--fastflag toswiftlint-smartfor quick iterations.4. Move SourceKit rules to CI-only
These are valuable but slow:
unused_import(analyzer rule)file_lengthRun them in CI, not on every save.
Impact
Related