When SwiftFormat and SwiftLint disagree, they can endlessly undo each other's work. Here is how to diagnose and resolve the conflict cleanly.
You run SwiftFormat, it changes some code, then SwiftLint complains or changes it back, and the next run flips it again. Your files never settle, and CI keeps failing on formatting even though you just formatted.
This tug-of-war happens because two tools are both trying to control the same stylistic detail. Each has its own opinion, and neither yields.
The symptom is distinctive: the same lines keep changing back and forth with no code changes of your own in between. Once you recognise that pattern, you know you are looking at a tool overlap rather than a bug in either program.
The conflict is frustrating but entirely fixable. The root cause is overlapping responsibilities, and the solution is to draw a clear boundary between the two tools.
Once that boundary exists, the churn stops and both tools go back to being useful instead of fighting each other. Nothing here requires deep expertise, only identifying the overlap and deciding who owns each contested detail.
SwiftFormat is a formatter. Its purpose is to rewrite code layout automatically. SwiftLint is primarily a linter, but it also includes rules about style and can be configured to autocorrect some of them.
When both tools have an enabled rule about the same thing, for example a particular kind of spacing or wrapping, they will each enforce their own version. One reformats, the other flags or reverts, and you get an infinite loop.
The two tools were built by different people with different defaults, so their opinions on a given detail need not match. Where the defaults happen to disagree, the overlap surfaces as churn.
Understanding this is the key insight. The tools are not buggy; they are simply both configured to own the same decision. Only one of them should.
Seeing the conflict this way turns a mysterious failure into a straightforward configuration task with a clear answer, because the fix is about ownership rather than about making the tools agree.
Start by finding exactly where the two tools disagree. Run each tool and note which specific stylistic change one makes that the other objects to.
The SwiftLint output usually names the rule that is triggering, and the SwiftFormat change is visible in your diff. Matching them up tells you precisely which pair is in conflict.
Work one conflict at a time. Look at a single line that keeps flipping, read the SwiftLint warning attached to it, and note the SwiftFormat rule most likely responsible for the layout it produced.
Resist the urge to fix this blindly by disabling large swaths of rules. Pinpoint the actual overlaps first.
Often it is only a handful of rules causing all the churn, and a targeted fix is far cleaner than a broad one. Disabling dozens of rules to silence two conflicts throws away valuable checks and leaves you with a weaker setup than necessary.
The guiding principle is simple: let each concern be owned by exactly one tool. For anything that is purely about code layout and formatting, let SwiftFormat be the authority.
For concerns that go beyond formatting, such as naming conventions, complexity limits, and other code-quality checks that SwiftFormat does not attempt, let SwiftLint be the authority.
This split maps naturally to what each tool is actually good at. SwiftFormat excels at mechanical layout, while SwiftLint excels at surfacing quality and convention issues that require judgement to fix.
Once you frame it as ownership, the resolution becomes obvious. Wherever the two overlap on a formatting detail, SwiftFormat wins and the corresponding SwiftLint rule is turned off.
This is the standard, widely recommended arrangement for teams using both. It is popular precisely because it is unambiguous: there is never a question of which tool decides a given detail, so the churn cannot recur.
With the overlaps identified and ownership decided, disable the SwiftLint rules that duplicate what SwiftFormat handles. SwiftLint is configured through its own configuration file where rules can be explicitly turned off.
Disable only the specific rules that conflict, not everything. The point is to remove the overlap while keeping all the valuable non-formatting checks SwiftLint provides.
List the exact rule identifiers you are disabling and, ideally, add a short comment next to each explaining that SwiftFormat owns that concern. That note prevents a future contributor from re-enabling the rule and restarting the conflict.
After disabling, run both tools again on the same files. The churn should stop, because now only SwiftFormat is making formatting decisions and SwiftLint no longer objects to them.
If a line still flips, there is likely another overlapping rule you have not yet found, so repeat the identification step until the files settle completely.
Even with clean ownership, the order in which you run the tools matters. If SwiftLint's autocorrect runs after SwiftFormat and touches formatting, you can reintroduce conflict.
A reliable pattern is to run the formatter first and the linter second, with the linter checking rather than rewriting formatting concerns. That way SwiftFormat establishes the layout and SwiftLint verifies quality without fighting it.
Running the formatter last is the common mistake, because whatever runs last gets the final say on the file. Letting SwiftFormat go first and SwiftLint merely inspect afterward keeps the layout stable.
Apply the same order consistently everywhere the tools run, including local hooks, build phases, and CI.
Inconsistent ordering between environments produces confusing results where code passes locally but fails in CI or vice versa. Pin the order in a shared script so it cannot drift between machines, which removes an entire category of hard-to-reproduce failures.
Once configured, test the full pipeline. Format and lint a project locally, then push and confirm CI agrees. The code should reach a stable state where running the tools again produces no further changes.
That stability is the sign the conflict is truly resolved. If files still change on repeated runs, there is a remaining overlap you have not yet addressed, so return to identifying the conflicting rule.
A quick way to test is to run the whole pipeline twice in a row on clean code. The second run should produce zero changes; any change means an unresolved conflict is still lurking.
Document the arrangement in your repository. A short note explaining that SwiftFormat owns formatting and which SwiftLint rules are intentionally disabled prevents a future contributor from re-enabling a rule and restarting the whole war.
Make sure both the SwiftFormat and SwiftLint configuration files are committed, so every machine and every CI run share the exact same resolved setup.
Both tools evolve, and updates can introduce new rules. When you upgrade either one, re-check for new overlaps, since a newly added default rule could reignite a conflict.
Treat a tool upgrade as a moment to run the two-runs test again. If the second run suddenly produces changes after an upgrade, a new default rule is the likely culprit, and disabling it restores stability.
Treating the two tools as complementary, with SwiftFormat handling layout and SwiftLint handling quality, keeps them productive partners rather than adversaries.
The mental model is what protects you long-term. As long as everyone understands the ownership boundary, new contributors and new tool versions can be absorbed without reopening the conflict.
Finally, keep perspective on what this work achieves. Resolving the conflict gives you clean, consistent, quality-checked source code. Neither tool builds, signs, or ships your app; that still requires Xcode and an Apple Developer Program membership.
Both tools have rules controlling the same stylistic detail, so one reformats and the other flags or reverts it. The fix is to give each concern a single owner and disable the overlapping rules in one tool.
For anything purely about code layout, let SwiftFormat be the authority and disable the duplicate SwiftLint rules. Let SwiftLint own non-formatting concerns like naming and complexity that SwiftFormat does not handle.
SwiftLint is configured through its own configuration file where you can explicitly turn off specific rules. Disable only the rules that duplicate SwiftFormat's formatting, keeping the rest.
Yes. Run the formatter first and the linter second, with the linter checking rather than rewriting formatting. Apply the same order in local hooks, build phases, and CI to avoid inconsistent results.
No. Both only affect source code style and quality checks. Building, signing, and App Store submission are handled by Xcode and require an Apple Developer Program membership.