- name
- swiftlint
- emoji
- \F9F9
- requires
- swiftlint
- install
- brew install swiftlint
- description
- Swift linting and style enforcement via CLI
SwiftLint
Enforce Swift style and conventions with static analysis. Lint entire projects, autocorrect fixable violations, manage rules, and integrate with Xcode and CI — all from the CLI.
Verify Installation
swiftlint versionIf not installed:
brew install swiftlintOr via Mint:
mint install realm/SwiftLintOr as a Swift Package Manager plugin (add to Package.swift):
.package(url: "https://github.com/realm/SwiftLint.git", from: "0.57.0")Then run:
swift package plugin swiftlintBasic Usage
Lint Current Directory
swiftlintThis recursively lints all .swift files from the current directory.
Lint a Specific Path
swiftlint lint --path Sources/Lint Specific Files
swiftlint lint --path Sources/App/ViewModel.swiftLint from Standard Input
cat MyFile.swift | swiftlint lint --use-stdin --quietAgent guidance: When a user says "check my code style" or "lint my Swift code," runswiftlintfrom the project root. If they point to a specific file or folder, use--path.
Autocorrect
SwiftLint can automatically fix certain violations.
Fix All Autocorrectable Violations
swiftlint --fixFix a Specific Path
swiftlint --fix --path Sources/Fix a Specific File
swiftlint --fix --path Sources/App/ViewModel.swiftPreview What Would Be Fixed (Dry Run)
Lint first to see violations, then fix:
swiftlint lint --path Sources/ && swiftlint --fix --path Sources/Agent guidance: Always lint before autocorrecting so the user sees what will change. Some violations are not autocorrectable — report those separately after fixing.
Output Formats
Default (Human-Readable)
swiftlintOutput: Sources/App.swift:12:1: warning: Line Length Violation: ...
JSON
swiftlint lint --reporter jsonCSV
swiftlint lint --reporter csvCheckstyle (XML)
swiftlint lint --reporter checkstyleGitHub Actions
swiftlint lint --reporter github-actions-loggingXcode Summary (plist)
swiftlint lint --reporter xcode-summarySonarQube
swiftlint lint --reporter sonarqubeMarkdown
swiftlint lint --reporter markdownSave to File
swiftlint lint --reporter json > swiftlint-results.jsonAll Available Reporters
| Reporter | Format | Best For |
|---|---|---|
xcode | Xcode-compatible (default) | Local development |
json | JSON array | Programmatic processing |
csv | CSV | Spreadsheet analysis |
checkstyle | XML | Jenkins, CI tools |
codeclimate | Code Climate JSON | Code Climate integration |
github-actions-logging | GitHub annotations | GitHub Actions CI |
sonarqube | SonarQube JSON | SonarQube integration |
markdown | Markdown table | PR comments |
emoji | Emoji-decorated | Fun terminal output |
html | HTML report | Browser viewing |
junit | JUnit XML | Test reporting tools |
xcode-summary | Plist | Xcode build summaries |
Agent guidance: Use--reporter jsonwhen you need to parse results programmatically. Use--reporter github-actions-loggingon GitHub Actions to get inline annotations on PRs.
Rules
List All Rules
swiftlint rulesSearch for a Specific Rule
swiftlint rules | grep "force_cast"Show Rule Details
swiftlint rules force_castRule Identifiers Quick Reference
Rules fall into categories:
Enabled by Default (Common)
| Rule | What It Catches |
|---|---|
line_length | Lines exceeding max length (default 120 warning, 200 error) |
trailing_whitespace | Whitespace at end of lines |
trailing_newline | Missing or extra trailing newlines |
opening_brace | Opening brace placement |
closing_brace | Closing brace placement |
colon | Colon spacing (e.g., let x : Int → let x: Int) |
comma | Comma spacing |
force_cast | Use of as! |
force_try | Use of try! |
force_unwrapping | Use of ! on optionals (opt-in) |
type_body_length | Type bodies exceeding max lines |
function_body_length | Function bodies exceeding max lines |
file_length | Files exceeding max lines |
cyclomatic_complexity | High cyclomatic complexity |
nesting | Deep nesting levels |
identifier_name | Naming convention violations |
type_name | Type naming convention violations |
unused_import | Unused import statements (opt-in) |
unused_declaration | Unused declarations (opt-in) |
vertical_whitespace | Excessive blank lines |
todo | TODO/FIXME comments as warnings |
mark | Improper MARK comment format |
void_return | Explicit -> Void instead of -> () |
syntactic_sugar | Prefer [Int] over Array<Int> |
redundant_optional_initialization | var x: Int? = nil (nil is default) |
redundant_string_enum_value | Enum case name matches raw value |
Opt-In (Must Be Explicitly Enabled)
| Rule | What It Catches |
|---|---|
explicit_type_interface | Missing explicit type annotations |
missing_docs | Missing documentation comments |
multiline_arguments | Multiline function call formatting |
multiline_parameters | Multiline function param formatting |
vertical_parameter_alignment | Parameter alignment in declarations |
sorted_imports | Unsorted import statements |
file_header | Missing or incorrect file headers |
accessibility_label_for_image | Images without accessibility labels |
accessibility_trait_for_button | Buttons without accessibility traits |
strict_fileprivate | Prefer private over fileprivate |
prohibited_interface_builder | Storyboard/XIB usage |
no_magic_numbers | Magic numbers in code |
prefer_self_in_static_references | Self over explicit type name in static context |
balanced_xctest_lifecycle | setUp without tearDown |
test_case_accessibility | Test methods not marked correctly |
Agent guidance: When setting up SwiftLint for a new project, start with defaults and only add opt-in rules the user specifically requests. Don't overwhelm with every possible rule.
Configuration (.swiftlint.yml)
SwiftLint reads .swiftlint.yml from the current directory (or parent directories).
Generate a Default Config
There's no built-in generator, but here's a minimal config:
# .swiftlint.yml
# Paths to include (default: all Swift files)
included:
- Sources
- Tests
# Paths to exclude
excluded:
- Pods
- DerivedData
- .build
- Packages
# Disable specific rules
disabled_rules:
- todo
- trailing_whitespace
# Enable opt-in rules
opt_in_rules:
- sorted_imports
- unused_import
- missing_docs
# Configure specific rules
line_length:
warning: 120
error: 200
ignores_comments: true
ignores_urls: true
type_body_length:
warning: 300
error: 500
file_length:
warning: 500
error: 1000
function_body_length:
warning: 50
error: 100
identifier_name:
min_length:
warning: 2
error: 1
max_length:
warning: 50
error: 60
excluded:
- id
- x
- y
- i
- j
- ok
type_name:
min_length:
warning: 3
error: 0
max_length:
warning: 50
error: 60
cyclomatic_complexity:
warning: 10
error: 20
nesting:
type_level:
warning: 2
function_level:
warning: 3Using a Config from a Custom Path
swiftlint lint --config path/to/.swiftlint.ymlMultiple Configs (Child Config)
# Feature/.swiftlint.yml — inherits parent config and overrides
child_config: ../.swiftlint.yml
disabled_rules:
- force_castParent Config (Extend from Another)
# .swiftlint.yml
parent_config: shared/.swiftlint-base.ymlRemote Config
parent_config: https://raw.githubusercontent.com/org/repo/main/.swiftlint.ymlAgent guidance: When a project already has .swiftlint.yml, always read it before suggesting changes. Modify the existing config rather than creating a new one.Inline Rule Management
Disable a Rule for a Line
let value = dict["key"] as! String // swiftlint:disable:this force_castDisable a Rule for a Block
// swiftlint:disable force_cast
let a = x as! String
let b = y as! Int
// swiftlint:enable force_castDisable All Rules for a Block
// swiftlint:disable all
// Legacy code that can't be refactored yet
// swiftlint:disable:enable allDisable for Next Line Only
// swiftlint:disable:next force_cast
let value = dict["key"] as! StringDisable for Previous Line
let value = dict["key"] as! String
// swiftlint:disable:previous force_castAgent guidance: Prefer targeted disables (disable:this,disable:next) over broad block disables. Never suggestdisable allunless the user is dealing with generated code or legacy code they explicitly don't want to lint.
Xcode Integration
Build Phase Script
Add a Run Script Phase in Xcode (Build Phases):
if command -v swiftlint >/dev/null 2>&1; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fiBuild Phase with Autocorrect
if command -v swiftlint >/dev/null 2>&1; then
swiftlint --fix && swiftlint
fiSwift Package Plugin (Xcode 15+)
If SwiftLint is added as a package dependency:
swift package plugin swiftlintOr in Xcode: right-click the project → "SwiftLintBuildToolPlugin".
Agent guidance: For modern projects (Xcode 15+), prefer the SPM plugin over a build phase script — it pins the SwiftLint version to the project and doesn't require a local install.
CI Integration
GitHub Actions
- name: SwiftLint
run: |
brew install swiftlint
swiftlint lint --reporter github-actions-logging --strictWith only changed files:
- name: SwiftLint Changed Files
run: |
git diff --name-only --diff-filter=d origin/main...HEAD -- '*.swift' | \
xargs -I{} swiftlint lint --path {} --reporter github-actions-logging --strictBitrise
- script:
inputs:
- content: |
brew install swiftlint
swiftlint lint --strictJenkins (Checkstyle)
swiftlint lint --reporter checkstyle > swiftlint-checkstyle.xmlThen use the Checkstyle plugin to parse swiftlint-checkstyle.xml.
Analyzing Results
Count Violations by Rule
swiftlint lint --reporter json | python3 -c "
import json, sys, collections
data = json.load(sys.stdin)
counts = collections.Counter(v['rule_id'] for v in data)
for rule, count in counts.most_common():
print(f'{count:>5} {rule}')
"Show Only Errors (Not Warnings)
swiftlint lint --strict 2>&1 | grep "error:"Strict Mode (Warnings Become Errors)
swiftlint lint --strictThis makes SwiftLint return a non-zero exit code for any violation (not just errors).
Quiet Mode (Errors Only in Output)
swiftlint lint --quietSuppresses warnings from output, only shows errors.
Enable/Disable Specific Rules via CLI
swiftlint lint --enable-rules sorted_imports,unused_import
swiftlint lint --disable-rules todo,trailing_whitespaceCustom Rules
Define custom regex-based rules in .swiftlint.yml:
custom_rules:
no_print_statements:
name: "No Print Statements"
regex: "\\bprint\\s*\\("
message: "Use os_log or Logger instead of print()"
severity: warning
match_kinds:
- identifier
no_hardcoded_strings:
name: "No Hardcoded Strings in Views"
regex: "Text\\(\"[^\"]+\"\\)"
message: "Use LocalizedStringKey or String(localized:) for user-facing text"
severity: warning
included: ".*View\\.swift"
no_force_unwrap_iboutlet:
name: "No Force Unwrap IBOutlet"
regex: "@IBOutlet\\s+(weak\\s+)?var\\s+\\w+:\\s+\\w+!"
message: "Use optional IBOutlets to avoid crashes"
severity: error
accessibility_identifier_required:
name: "Accessibility Identifier"
regex: "\\.accessibilityIdentifier\\("
message: "Good — accessibilityIdentifier found"
severity: warning
match_kinds:
- identifier
prefer_logger_over_print:
name: "Prefer Logger"
regex: "\\bNSLog\\s*\\("
message: "Use Logger (os.Logger) instead of NSLog"
severity: warningMatch Kinds
| Kind | What It Matches |
|---|---|
identifier | Variable/function names |
string | String literals |
comment | Comments |
keyword | Swift keywords |
typeidentifier | Type names |
number | Numeric literals |
parameter | Function parameters |
argument | Function arguments |
Agent guidance: Custom rules are powerful but regex-based — they can produce false positives. Always test custom rules on the codebase before suggesting them as permanent additions.
Common Flags Reference
| Flag | Purpose |
|---|---|
--path <path> | Lint specific file or directory |
--config <path> | Use custom config file |
--reporter <name> | Output format (json, csv, etc.) |
--strict | Treat warnings as errors |
--quiet | Only show errors in output |
--fix | Autocorrect fixable violations |
--enable-rules <rules> | Enable specific rules (comma-separated) |
--disable-rules <rules> | Disable specific rules (comma-separated) |
--use-stdin | Read Swift from stdin |
--force-exclude | Exclude files even if explicitly passed |
--cache-path <path> | Custom cache directory |
--no-cache | Disable caching |
--use-alternative-excluding | Use alternative file-excluding method |
--in-process-sourcekit | Use in-process SourceKit |
--compiler-log-path | Path to xcodebuild log for analyzer rules |
--progress | Show progress bar |
Common Workflows
Set Up SwiftLint for a New Project
# 1. Install
brew install swiftlint
# 2. Run initial lint to see baseline
swiftlint lint --path Sources/ --reporter json > baseline.json
# 3. Create config based on results
cat > .swiftlint.yml << 'EOF'
included:
- Sources
- Tests
excluded:
- Pods
- DerivedData
- .build
disabled_rules:
- todo
opt_in_rules:
- sorted_imports
- unused_import
line_length:
warning: 120
error: 200
ignores_urls: true
EOF
# 4. Fix autocorrectable issues
swiftlint --fix --path Sources/
# 5. Re-lint to see remaining issues
swiftlintFix All Issues Before a PR
# Autocorrect what we can
swiftlint --fix
# Check what remains
swiftlint lint --strictLint Only Changed Files (vs. main)
git diff --name-only --diff-filter=d origin/main...HEAD -- '*.swift' | \
xargs -I{} swiftlint lint --path {} --strictCompare Violation Counts Between Branches
# Current branch count
CURRENT=$(swiftlint lint --quiet 2>&1 | wc -l | tr -d ' ')
# Main branch count
git stash
git checkout main
MAIN=$(swiftlint lint --quiet 2>&1 | wc -l | tr -d ' ')
git checkout -
git stash pop
echo "main: $MAIN violations, current: $CURRENT violations"Troubleshooting
Common Errors
| Error | Solution |
|---|---|
No lintable files found | Check included paths in config or run from project root |
Invalid configuration | Validate YAML syntax in .swiftlint.yml |
SourceKit not found | Run sudo xcode-select -s /Applications/Xcode.app |
Rule not found | Check rule name with swiftlint rules, may be opt-in |
Slow linting | Add excluded paths for Pods/DerivedData, use --cache-path |
Performance Tips
- Always exclude
Pods/,DerivedData/,.build/, andPackages/in config - Use
--cache-pathto persist cache across CI runs - Lint only changed files on CI instead of the entire project
- Use
--no-cacheonly when debugging unexpected results
Notes
Agent Tips
When a user asks to "clean up" or "fix style" in Swift code, runswiftlint --fixfirst, thenswiftlint lintto report remaining issues.
Before adding SwiftLint to an existing project, run swiftlint lint --reporter json to assess the violation count. If there are hundreds of violations, suggest a phased approach: fix autocorrectable ones first, then tackle the rest by category.Always check for an existing .swiftlint.yml before creating one. Read it to understand the team's style preferences.For projects targeting accessibility (which should be all of them), suggest enablingaccessibility_label_for_imageandaccessibility_trait_for_buttonopt-in rules.
When the user's project uses SwiftUI, suggest a custom rule to catch hardcoded strings inText()views — all user-facing strings should useString(localized:)for localization support.
The --strict flag is essential for CI — without it, SwiftLint exits 0 even with warnings, which means your CI pipeline won't catch style regressions.